简体   繁体   中英

How can I filter a nested object with dynamic filters using Lodash or plain javascript?

I have the following data:

const products = [{
 name: "Product 1",
 options: [
  {
    id: 1,
    optionName: "Color",
    value: "Red" 
  },
  { 
    id: 2,
    optionName: "Size",
    value: "Small" 
  }
 ]},
{
 name: "Product 2",
 options: [
  {
    id: 1,
    optionName: "Color",
    value: "Red" 
  },
  { 
    id: 2,
    optionName: "Size",
    value: "Large" 
  }
 ]}];

And I have a filter object, that is created dynamically:

let selectedFilters = {"Color":"Red", "Size":"Small"};

I want to get only the products that meet all the criteria specified in the selectedFilters object. In the example, I should only get "Product 1"

This is what I have tried so far but none of these work as I need:

let filteredProducts = [];
let keys = Object.keys(selectedFilters);
keys.forEach(function(filterKey) {
  let f = _.filter(products, function(o) {
    let flag = false;
    let searchFilterKey = selectedFilters[filterKey];
    let index = o.options.findIndex(o=> o.optionName == filterKey && o.value == searchFilterKey);
    if (index > 0)
      return o;
  });
  filteredProducts = f;
});
products.filter(p => 
    Object.keys(selectedFilters).every(k => 
    {
      return p.options.filter(o => o.optionName == k && o.value == selectedFilters[k]);
    }));

You could get the values of the filter in an array and run an every function with a matching condition. Since the 'value' is the significant property here use it to run its value against the selectedFilters.

Do the same for the keys if you they are part of the criteria

 const products = [{ name: "Product 1", options: [{ id: 1, optionName: "Color", value: "Red" }, { id: 2, optionName: "Size", value: "Small" } ] }, { name: "Product 2", options: [{ id: 1, optionName: "Color", value: "Red" }, { id: 2, optionName: "Size", value: "Large" } ] } ] let selectedFilters = { "Color": "Red", "Size": "Small" }; const arrFilterValues = Object.values(selectedFilters); const arrFilterKeys = Object.keys(selectedFilters); const result = products.filter(x => { return x.options.every(y=> arrFilterValues.includes(y['value']) && arrFilterKeys.includes(y['optionName'])) }) console.log(result)

You can filter based on the entries of the object.

 const products = [{ name: "Product 1", options: [ { id: 1, optionName: "Color", value: "Red" }, { id: 2, optionName: "Size", value: "Small" } ]}, { name: "Product 2", options: [ { id: 1, optionName: "Color", value: "Red" }, { id: 2, optionName: "Size", value: "Large" } ]}]; let selectedFilters = {"Color":"Red", "Size":"Small"}; let entries = Object.entries(selectedFilters); const res = products.filter(({options})=> entries.every(([k,v])=>options.some(o=>o.optionName===k && o.value === v))); console.log(res);

You can get the result with Array#filter , Array#every and Array#some . The filter-array can be dynamical extended and it's not necessary that it is sorted or that all of filter-properties be present.

I filter over the product-array. Here had for every product, which will be selected, all filters of the filter-array to be fullfilled. For every filter-criterium I look if this criteria is for some options for this product ok. For this had the optionname and the value to match.

 function myFilter(array, filters) { return array.filter(({options}) => Object.entries(filters).every(([key, value]) => options.some((option) => option.optionName===key && option.value===value ) ) ); } const products = [{ name: "Product 1", options: [ { id: 1, optionName: "Color", value: "Red" }, { id: 2, optionName: "Size", value: "Small" } ]}, { name: "Product 2", options: [ { id: 1, optionName: "Color", value: "Red" }, { id: 2, optionName: "Size", value: "Large" } ]}]; let filters= {"Color":"Red", "Size":"Small"}; console.log(myFilter(products, filters));

You can try to use Array.filter , and then use Array.every function foreach product.options to check if it's properties exist in the selectedFilters object.

const products = [{
  name: "Product 1",
  options: [
    {
      id: 1,
      optionName: "Color",
      value: "Red" 
   },
   { 
      id: 2,
      optionName: "Size",
      value: "Small" 
   }
  ]
},
{
  name: "Product 2",
  options: [
    {
      id: 1,
      optionName: "Color",
      value: "Red" 
    },
    { 
      id: 2,
      optionName: "Size",
      value: "Large" 
    }
  ]
 }
];

let selectedFilters = {"Color":"Red", "Size":"Small"};

let filteredProducts = products.filter(product => {
    return product.options.every(({ optionName, value }) => !!selectedFilters[optionName] && selectedFilters[optionName] === value);
});

console.log(filteredProducts);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM