I have 2 arrays structured like this :
const products = [
{
id: 1,
name: 'Table',
attributes: [
{ id: 13, prodId: 1, attribute_id: 1, attribute_value_id: 8 },
{ id: 14, prodId: 1, attribute_id: 2, attribute_value_id: 19 },
{ id: 15, prodId: 1, attribute_id: 3, attribute_value_id: 88 },
{ id: 16, prodId: 1, attribute_id: 4, attribute_value_id: 237 },
],
},
{
id: 2,
name: 'Chair',
attributes: [
{ id: 25, prodId: 2, attribute_id: 1, attribute_value_id: 2 },
{ id: 26, prodId: 2, attribute_id: 2, attribute_value_id: 21 },
{ id: 27, prodId: 2, attribute_id: 3, attribute_value_id: 127 },
{ id: 28, prodId: 2, attribute_id: 4, attribute_value_id: 240 },
],
},
{
id: 3,
name: 'Couch',
attributes: [
{ id: 41, prodId: 3, attribute_id: 1, attribute_value_id: 8 },
{ id: 42, prodId: 3, attribute_id: 2, attribute_value_id: 18 },
{ id: 43, prodId: 3, attribute_id: 3, attribute_value_id: 88 },
{ id: 44, prodId: 3, attribute_id: 5, attribute_value_id: 271 },
],
},
{
id: 4,
name: 'Rug',
attributes: [
{ id: 75, prodId: 4, attribute_id: 1, attribute_value_id: 2 },
{ id: 76, prodId: 4, attribute_id: 2, attribute_value_id: 19 },
{ id: 77, prodId: 4, attribute_id: 3, attribute_value_id: 89 },
{ id: 78, prodId: 4, attribute_id: 4, attribute_value_id: 256 },
],
},
]
const filters = [
{ attribute_id: 1, attribute_value_id: '8' },
{ attribute_id: 3, attribute_value_id: '88' },
]
How can I filter objects from the "products" array that matches at least all criteria from the "filters" array, no matter how many products are there, nor how many attributes each product has ?
In the above case, I would like to get the result :
[{
id: 1,
name: 'Table',
attributes: [
{ id: 13, prodId: 1, attribute_id: 1, attribute_value_id: 8 },
{ id: 14, prodId: 1, attribute_id: 2, attribute_value_id: 19 },
{ id: 15, prodId: 1, attribute_id: 3, attribute_value_id: 88 },
{ id: 16, prodId: 1, attribute_id: 4, attribute_value_id: 237 },
],
},
{
id: 3,
name: 'Couch',
attributes: [
{ id: 41, prodId: 3, attribute_id: 1, attribute_value_id: 8 },
{ id: 42, prodId: 3, attribute_id: 2, attribute_value_id: 18 },
{ id: 43, prodId: 3, attribute_id: 3, attribute_value_id: 88 },
{ id: 44, prodId: 3, attribute_id: 5, attribute_value_id: 271 },
],
}]
Edit : I've tried to start from something like this :
const filteredProducts = products.filter((p)=>{
return filters.some((f)=>{
// another loop ?
});
});
console.log(filteredProducts);
but couldn't manage to loop through each product's nested attributes and through filters when there's many of them
NB : product "couch" having an attribute with "attribute_id" of 5 instead of 4 is not a typo
Hoping I'm clear enough, thanks in advance !
CodePudding user response:
Yes, you need another loop.
From what you've said ... at least all criteria from the "filters", you'd have to use filters.every
and not filters.some
. And then for each you'll have to iterate over the key value pairs (Object.entries
) and see if any of the objects in the attributes
array matches (use some
).
So use combinations of every and
some`, like so:
function filterByAttributes(products, filters) {
return products.filter(({attributes}) =>
filters.every(filter =>
Object.entries(filter).every(([key, value]) =>
attributes.some(obj => obj[key] == value)
)
)
);
}
const products = [{id: 1,name: 'Table',attributes: [{ id: 13, prodId: 1, attribute_id: 1, attribute_value_id: 8 },{ id: 14, prodId: 1, attribute_id: 2, attribute_value_id: 19 },{ id: 15, prodId: 1, attribute_id: 3, attribute_value_id: 88 },{ id: 16, prodId: 1, attribute_id: 4, attribute_value_id: 237 },],},{id: 2,name: 'Chair',attributes: [{ id: 25, prodId: 2, attribute_id: 1, attribute_value_id: 2 },{ id: 26, prodId: 2, attribute_id: 2, attribute_value_id: 21 },{ id: 27, prodId: 2, attribute_id: 3, attribute_value_id: 127 },{ id: 28, prodId: 2, attribute_id: 4, attribute_value_id: 240 },],},{id: 3,name: 'Couch',attributes: [{ id: 41, prodId: 3, attribute_id: 1, attribute_value_id: 8 },{ id: 42, prodId: 3, attribute_id: 2, attribute_value_id: 18 },{ id: 43, prodId: 3, attribute_id: 3, attribute_value_id: 88 },{ id: 44, prodId: 3, attribute_id: 5, attribute_value_id: 271 },],},{id: 4,name: 'Rug',attributes: [{ id: 75, prodId: 4, attribute_id: 1, attribute_value_id: 2 },{ id: 76, prodId: 4, attribute_id: 2, attribute_value_id: 19 },{ id: 77, prodId: 4, attribute_id: 3, attribute_value_id: 89 },{ id: 78, prodId: 4, attribute_id: 4, attribute_value_id: 256 },],},]
const filters = [{ attribute_id: 1, attribute_value_id: '8' },{ attribute_id: 3, attribute_value_id: '88' },];
console.log(filterByAttributes(products, filters));