I have a "products" array that consists of multyple objects like the one in the array bellow. The actual array has more products with more prices, images, etc., but the structure for all of them is the same.
const products = [
{
"id": "some_id",
"name": "some_name",
"brand": "some_brandName",
"inStock": true,
"gallery": [
"some_url_to_image"
],
"category": "some_category_name",
"attributes": [
{
"id": "Size",
"name": "Size",
"type": "text",
"items": [
{
"displayValue": "40",
"value": "40",
"id": "40"
},
{
"displayValue": "41",
"value": "41",
"id": "41"
},
{
"displayValue": "42",
"value": "42",
"id": "42"
},
{
"displayValue": "43",
"value": "43",
"id": "43"
}
]
},
{
"id": "Color",
"name": "Color",
"type": "swatch",
"items": [
{
"displayValue": "Green",
"value": "#44FF03",
"id": "Green"
},
{
"displayValue": "Cyan",
"value": "#03FFF7",
"id": "Cyan"
},
{
"displayValue": "Blue",
"value": "#030BFF",
"id": "Blue"
},
{
"displayValue": "Black",
"value": "#000000",
"id": "Black"
},
{
"displayValue": "White",
"value": "#FFFFFF",
"id": "White"
}
]
},
{
"id": "Capacity",
"name": "Capacity",
"type": "text",
"items": [
{
"displayValue": "512G",
"value": "512G",
"id": "512G"
},
{
"displayValue": "1T",
"value": "1T",
"id": "1T"
}
]
}
],
"prices": [
{
"currency": {
"label": "USD",
"symbol": "$"
},
"amount": 55.00
},
]
},
];
I also have a "filters" array of objects that contain the values of one or more parameters thast need to be used to filter out the "products" array.
const filters = [
{
"name": "Color",
"value": "FFFFFF"
},
{
"name": "Size",
"value": "42"
}
];
The problem
I want to use the values found in the "filters" array to filter out the "products" array to only contain the products whose "products[index].attributes" array contains all the key/value pairs in the "filters" array. For example, if the "filters" array has an object with the name "Size" and value "42", then the "products" array should be filtered to only consists of the product's whose "attributes" array contain those values.
I understand that Javascript has the .filter() method, and I know how to use it to filter out a simple array, but when it comes to such an array with many nested objects, etc., I have no idea how to acomplish this without using a crazy amount of nested functions.
What would be the fastest/simplest way to filter out the list?
CodePudding user response:
const products = [
{
"id": "some_id",
"name": "some_name",
"brand": "some_brandName",
"inStock": true,
"gallery": [
"some_url_to_image"
],
"category": "some_category_name",
"attributes": [
{
"id": "Size",
"name": "Size",
"type": "text",
"items": [
{
"displayValue": "40",
"value": "40",
"id": "40"
},
{
"displayValue": "41",
"value": "41",
"id": "41"
},
{
"displayValue": "42",
"value": "42",
"id": "42"
},
{
"displayValue": "43",
"value": "43",
"id": "43"
}
]
},
{
"id": "Color",
"name": "Color",
"type": "text",
"items": [
{
"displayValue": "FFFFFF",
"value": "FFFFFF",
"id": "FFFFFF"
}
]
},
],
"prices": [
{
"currency": {
"label": "USD",
"symbol": "$"
},
"amount": 55.00
},
]
},
];
const filters = [
{
"name": "Color",
"value": "FFFFFF"
},
{
"name": "Size",
"value": "40"
}
];
// So ofcourse we want to write a filter to filter out the products we want
let filtered = products.filter( (p) => {
let filteredOut = false
// We have multiple filters, so we have to foreach those
filters.forEach((filter) => {
// Now we have to find the correct attribute to check our value with
currentAttribute = p.attributes.find(product => p.name = filter.name)
// We have multiple options to check with so also foreach this
currentAttribute.items.forEach(item => {
if (filter.value === item.value) {
// If we find one, we return because we just want one hit
filteredOut = true
return
}
})
})
return filteredOut
})
console.log(filtered)
CodePudding user response:
I tried using @Wimanicesir 's answer, but it returned some errors ('can't read undefined') and did not filter the product list based on multyple parameters. Instead, the 'filterProductList' function I wrote filters the product list and throws no errors. Thank you @Wimanicesir for reminding me about .find(), that helpt me to shorten the code I had before.
const products = [
{
"id": "some_id",
"name": "some_name",
"brand": "some_brandName",
"inStock": true,
"gallery": [
"some_url_to_image"
],
"category": "some_category_name",
"attributes": [
{
"id": "Size",
"name": "Size",
"type": "text",
"items": [
{
"displayValue": "40",
"value": "40",
"id": "40"
},
{
"displayValue": "41",
"value": "41",
"id": "41"
},
{
"displayValue": "42",
"value": "42",
"id": "42"
},
{
"displayValue": "43",
"value": "43",
"id": "43"
}
]
},
{
"id": "Color",
"name": "Color",
"type": "text",
"items": [
{
"displayValue": "FFFFFF",
"value": "FFFFFF",
"id": "FFFFFF"
}
]
},
],
"prices": [
{
"currency": {
"label": "USD",
"symbol": "$"
},
"amount": 55.00
},
]
},
];
const filters = [
{
"name": "Color",
"value": "FFFFFF"
},
{
"name": "Size",
"value": "40"
}
];
const filterProductList = (filters, products) => {
return products.filter(product => filters.every(filter => {
const key = product.attributes.find(attribute => attribute.name === filter[0]);
const value = key !== undefined ? key.items.find(item => item.value === filter[1]) : undefined;
const filteredProduct = value !== undefined ? product : false;
return filteredProduct;
}))
}
console.log(filterProductList(filters, products));