ES6 - Finding data in nested arrays
In ES6 using find
or filter
I'm quite comfortable iterating through to find an element in an array using a value.
However, I'm trying to get a value from a parent array based upon a value from a nested array.
For example, in this data structure:
products: [
{
id: 01,
items: [
{
id: 01,
name: 'apple'
},
{
id: 02,
name: 'banana'
},
{
id: 03,
name: 'orange'
}
]
},
{
id: 02,
items: [
{
id: 01,
name: 'carrot'
},
{
id: 02,
name: 'lettuce'
},
{
id: 03,
name: 'peas'
}
]
},
{
id: 03,
items: [
{
id: 01,
name: 'eggs'
},
{
id: 02,
name: 'bread'
},
{
id: 03,
name: 'milk'
}
]
}
]
If I know the name
or id
of the object milk
, is there a way to find out the id of the element it's nested within?
Currently I have this:
products.find((product) => {
product.find((prod) => {
return prod.name === 'milk';
});
});
Which only returns the object containing milk
.
You have to return something from the callback of the outer find
. In fact, for the inner iteration you shouldn't use find
but rather some
that returns a boolean for whether an element matching the condition exists within the arrray:
products.find((product) => {
return product.items.some((item) => {
//^^^^^^
return item.name === 'milk';
});
});
or in short:
products.find(product => product.items.some(item => item.name === 'milk'));
Then check whether find
found something (not null
!) and get its .id
, the result should be 03
. Alternatively, you can filter
for the products containing milk as an item and then map all the results to their id:
products.filter(product =>
product.items.some(item => item.name === 'milk');
).map(product =>
product.id
) // [03]
The accepted answer didn't do it for me because I wanted the result of the inner find, using both it always gave me the result of the outer filter/find, and I had to use the resulting array to find the value again.
So instead I used reduce with short-circuit to get the inner result.
// undefined as the initial value is necessary, otherwise it gets the first value of the array instead.
return products.reduce((prev, product) => prev || product.items.find(item => item.name === 'milk'), undefined);
const products = [
{id: 1, items: [
{id: 1, name: 'apple'},
{id: 2, name: 'banana'},
{id: 3, name: 'orange'}
]},
{id: 2, items: [
{id: 1, name: 'carrot'},
{id: 2, name: 'lettuce'},
{id: 3, name: 'peas'}
]},
{id: 3, items: [
{id: 1, name: 'eggs'},
{id: 2, name: 'bread'},
{id: 3, name: 'milk'}
]}
];
console.log(products.reduce((prev, product) => prev || product.items.find(item => item.name === 'milk'), undefined));
I know you mention ES6, but in this case (and if you want to return the inner object) I believe it's better using for
/of
instead of map
/reduce
/find
:
for (let p of products) {
for (let i of p.items) {
if (i.name === 'milk') return i;
}
}