Finding nested categories using js underscore
This is how my data object looks like http://jsfiddle.net/303tpLtz/
As you can see here there are categories within categories that need to be considered when doing a search
So the problem is that I can find the top level names of the categories using _.findWhere(result.response.categories, {name: 'Arts & Entertainment'})
But the problem is when I need to find something mentioned inside the supplied query. For example, if I need to find a restaurant that is inside Food>
Can anyone help me with Deep search function?
My convoluted jsFiddle solution :
function findDeep(cats, attrs) {
_.each(cats, function(data, i) {
var copy = data;
// delete copy.categories;
newArr.push(copy);
_.each(data.categories, function(newObj) {
var copy2 = newObj;
// delete copy2.categories;
newArr.push(copy2)
if (newObj.categories) {
_.each(newObj.categories, function(otherObj) {
var copy3 = otherObj;
// delete copy3.categories;
newArr.push(copy3)
})
}
})
});
return _.findWhere(newArr, attrs) || null;
}
source to share
The problem with this data is that each node potentially needs to be further validated, which means you cannot neatly apply a filter to each element, since the missing elements themselves may have nested categories that you need to validate.
However, using plain javascript or alternatively using _. reduce and a bit of recursive magic , we can only get the job done with a little bit of code.
function findMatchingCategories(cats, attrs) {
return _.filter(extractCategories(cats), attrs);
function extractCategories(cats) {
return _.reduce(cats, function (result, value) {
return result.concat([value]).concat(value.categories ? extractCategories(value.categories) : []);
}, []);
}
}
console.log(findMatchingCategories(data, { name: 'Tunnel' }));
Explain:
_.reduce
allows you to view a dataset and track a progressively βscaled-downβ data variable. In our case, we are reducing the set of categories to a new named array result
that contains only all nested categories. To make sure we check all nested categories as well, we recursively call extractCategories
and use it to add it to the minified array of results.
Finally, we are left with categories, nested or not, which we then filter based on attr
.
A more efficient version with less concatenation:
function findMatchingCategories(cats, attrs) {
return _.filter(extractCategories(cats, []), attrs);
function extractCategories(currentCats, allCats) {
_.each(currentCats, function (value) {
allCats.push(value);
if (value.categories) {
extractCategories(value.categories, allCats);
}
}, []);
return allCats;
}
}
console.log(findMatchingCategories(data, { name: 'Tunnel' }));
The more we work, the less concise the code will be.
source to share