How to query objects, each by its ID, from a nested data structure
Solution 1:
Array.prototype.find
helps one to find an object within an array, and Object.values
returns all of an object's values as array, whereas Array.prototype.flat
helps flattening an array of arrays.
The beneath implementation also uses an Arrow function expressions as find
's callback function together with a destructuring_assignment which is applied for unpacking a field from an object passed as a parameter to the callback.
function findObjectByID(obj, id) {
return Object
.values(obj)
.flat()
.find(({ ID }) => ID === id);
}
const sampleData = {
FL: [{ ID: 1, confirmed: true }, { ID: 2, confirmed: false }],
TX: [{ ID: 3, confirmed: true }],
NY: [{ ID: 4, confirmed: false }, { ID: 5, confirmed: true }],
};
console.log(
'findObjectByID(sampleData, 2) ...',
findObjectByID(sampleData, 2)
);
console.log(
'findObjectByID(sampleData, 3) ...',
findObjectByID(sampleData, 3)
);
console.log(
'findObjectByID(sampleData, 5) ...',
findObjectByID(sampleData, 5)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
An even better approach, in case the OP has to query very often and repeatedly objects from the original data structure, was to transform this structure exactly once into a flat object which then serves as ID
based map or index for custom data items (e.g. each item keeps the relation to its original category or meta key like 'FL'
, 'TX'
or 'NY'
).
The above provided example code then will be refactored into the next following one like that ...
function createIdBasedItemIndex(rawData) {
return Object
.entries(rawData)
.flatMap(([category, itemList]) =>
itemList.map(item => ({ category, item }))
)
.reduce((index, data) =>
Object.assign(index, { [data.item.ID]: data }), {}
);
}
const sampleData = {
FL: [{ ID: 1, confirmed: true }, { ID: 2, confirmed: false }],
TX: [{ ID: 3, confirmed: true }],
NY: [{ ID: 4, confirmed: false }, { ID: 5, confirmed: true }],
};
const categoryItemIndex = createIdBasedItemIndex(sampleData);
console.log({ sampleData, categoryItemIndex });
console.log('categoryItemIndex[2] ...', categoryItemIndex[2]);
console.log('categoryItemIndex[3] ...', categoryItemIndex[3]);
console.log('categoryItemIndex[5] ...', categoryItemIndex[5]);
.as-console-wrapper { min-height: 100%!important; top: 0; }
Solution 2:
Here's a method that preserves the key as well as returning the match.
let obj = {
FL: [{ID: 1, confirmed: true},{ID: 2, confirmed: false}],
TX: [{ID: 3, confirmed: true}],
NY: [{ID: 4, confirmed: false}, {ID: 5, confirmed: true}]
}
const findFromId = (obj, id) => {
for (let x in obj) {
if (res = obj[x].find(a => a.ID == id)) return { [x]: res }
}
return null;
}
console.log(findFromId(obj, 5))