1

I am trying to make a filter for this information, this is an array of objects from a API with the information of all the products in the database, in this example I only show one product, but the API request all products.

[
        {
            "Id": 11,
            "Name": "Papas fritas",
            "Description": "Papas",
            "Availability": 1,
            "Price": 1,
            "Stock": 10,
            "Promotion": 0,
            "Discount": 0,
            "Visible": 1,
            "CreationDate": "2021-04-22T18:51:51.000Z",
            "UpdateAt": null,
            "Photo": [
                {
                    "Id": 21,
                    "Photo": "photo.png"
                }
            ],
            "Rating": 4.5,
            "Category": [
                {
                    "Id": 2,
                    "Category": "Moda",
                    "Icon": "Fashion"
                },
                {
                    "Id": 3,
                    "Category": "Fitness",
                    "Icon": "Fitness"
                }
            ],
            "Subcategory": [],
            "Characteristics": [],
  
}

Now I make a class that have the methods for short and filter this array, but I have a problem filtering the information, I don't know how to filter the information by category using something like this:

[{Category: 'Art,Fitnness'}]

It's also is possible that the Promotion property will be formatted this way:

[{Promotion: 'true'}]

As you can see this array with the filters can have more than one property and can be a different property than category i need to validate the values because all values in the array are strings and sometimes Array.filter doesn't work comparing a string "true" === 1

What I implement for this is this function, query is the array of the products and queryvalues is the filter array

FilterFuntion(Query, QueryValues)
{
    QueryValues = Object.entries(QueryObj).map((e) => ( { [e[0]]: e[1] } ));
    
    let FilteredArray = Query;

    QueryValues.map((Filter) =>
    {
        var key = Object.keys(Filter)[0];

        FilteredArray = ValidateFilter(key, Filter[key], FilteredArray);
    });

    return FilteredArray;
}

ValidateFilter(Key, Value, array)
{
        return array.filter((El) => 
        {
            if (Value === "true" || Value === "false")
            {
                return Boolean(El[Key]) === Boolean(Value);
            }

            if(Array.isArray((El[Key]))
            {
                 (El[Key]).filter((sub) => 
                 {
                     return String(sub[Key]) === String(Value);
                 });           
            }

            return String(El[Key]) === String(Value);
        });
}

So I validate if the value of the filter is a bool string or int first and next I return the value that match, that work correct whit all the normal values but when the value nested in another array doesn't work, it returns a filter array of category instead of return the entire product, I don't know how to make this work when there are nested arrays, and when I would want to filter on multiple categories, how can I do it ?.

[{Category: 'Art,Fitnness'}]

Another thing is for example when the filter has a value between two numbers, for example look Rating property, I need to filter and return only the products that have a rating between 5 and 4

[{Promotion: 'true'}, {Category: 'Fitness'}, {Rating: '5,4'}]

1 Answer 1

1

Using filter, we can take each object from the array and test whether or not it meets the criteria.

Here is the anatomy of the filter object:

filter = {
      Rating: [3, 5],
      Category: [
        ['Fitness','Moda'],
        ['OtherCategory']
      ],
      Promotion: 'false'
    }

Rating is an array for 'between' - if you're looking for an exact number, just put it in twice ([4.5,4.5]). Category is an array of arrays and takes care of or/and like this:

  [
    ['Fitness','Moda'], // product has both categories 'Fitenss' and 'Moda'
    ['OtherCategory'] // OR product has 'OtherCategory'
  ]

const data = [{
    "Id": 11,
    "Name": "Papas fritas",
    "Description": "Papas",
    "Availability": 1,
    "Price": 1,
    "Stock": 10,
    "Promotion": 0,
    "Discount": 0,
    "Visible": 1,
    "CreationDate": "2021-04-22T18:51:51.000Z",
    "UpdateAt": null,
    "Photo": [{
      "Id": 21,
      "Photo": "photo.png"
    }],
    "Rating": 4.5,
    "Category": [{
        "Id": 2,
        "Category": "Moda",
        "Icon": "Fashion"
      },
      {
        "Id": 3,
        "Category": "Fitness",
        "Icon": "Fitness"
      }
    ],
    "Subcategory": [],
    "Characteristics": []

  },
  {
    "Id": 13,
    "Name": "Papas fritas2",
    "Description": "Papas2",
    "Availability": 1,
    "Price": 1,
    "Stock": 10,
    "Promotion": 0,
    "Discount": 0,
    "Visible": 1,
    "CreationDate": "2021-04-22T18:51:51.000Z",
    "UpdateAt": null,
    "Photo": [{
      "Id": 21,
      "Photo": "photo.png"
    }],
    "Rating": 3.5,
    "Category": [{
      "Id": 2,
      "Category": "OtherCategory",
      "Icon": "Fashion"
    }],
    "Subcategory": [],
    "Characteristics": []

  }
]

//[{Promotion: 'true'}, {Category: 'Fitness'}, {Rating: '5,4'}]


const filterProductsBy = (criteria, data) => {
  let p = data.filter(obj => {
    let isMatch = true;
    if (criteria.Rating && (obj.Rating < criteria.Rating[0] || obj.Rating > criteria.Rating[1])) isMatch = false;
    if (criteria.Category) {
      let catMatch = false
      // prepare the cat array
      let cats = obj.Category.map(c => c.Category);
      criteria.Category.forEach(set =>
        set.forEach(catAnd => {
          console.log(cats, catAnd, cats.includes(catAnd))
          if (cats.includes(catAnd)) catMatch = true;
        })
      )
      if (!catMatch) isMatch = false;
    }



    if (criteria.Subcategory) {
      let catMatch = false
      // prepare the Subcategory array
      let subcats = obj.Subcategory.map(c => c.Subcategory);
      criteria.Subcategory.forEach(set =>
        set.forEach(catAnd => {
          //console.log(subcats, catAnd, subcats.includes(catAnd))
          if (subcats.includes(catAnd)) catMatch = true;
        })
      )
      if (!catMatch) isMatch = false;
    }



    obj.Promotion = obj.Promotion === 0 ? 'false' : 'true';
    if (criteria.Promotion && obj.Promotion != criteria.Promotion) isMatch = false;


    return isMatch;

  })

  return p

}

let filter = {
  Rating: [3, 5],
  Category: [
    ['Fitness']
  ],
  Promotion: 'false'
}

console.log(filterProductsBy(filter, data))


filter = {
  Rating: [3, 5],
  Category: [
    ['Fitness'],
    ['OtherCategory']
  ],
  Promotion: 'false'
}

console.log(filterProductsBy(filter, data))

Sign up to request clarification or add additional context in comments.

11 Comments

Actually, I misread the question. I will update my answer to show how to filter the data the way you asked about...
This filter you made, don't return the product
@LuisDanielMonsalveRuiz - check now. I created a filter function that should do the trick.
The code to accomplish this would benefit from TypeScript wherein your filtering functions could take in defined types. That is, if it is feasible to use in your project.
Bro this works amazing really thanks, can you make this like i can pass the key value insteand of criteria.category because i neeed to do this whit subcategory and other more for others objects
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.