So I have a javascript array that looks like this (simplified).
Here beauty (id:1
) and health (id:2
) is root categories as they have a null value of parentCategoryId
.
hair care (id:3
), hair oil (id:4
) and kumarika hair oil (id:5
) falls into the beauty category(id:1
) as they have parentCategoryId
value which directly or indirectly falls into beauty category(see below for explaination).But supplements (id:6
) falls into the health category (id:2
).
How do I get all the categories that (directly or nested) falls into the beauty category (id:1
).
key parentCategoryId
is the identifier of which category directly falls into which category.
so here
id:3
has parentCategoryId:1
that means id:3
is direct children of id:1
.So falls into beauty category.
id:4
has parentCategoryId:3
that means id:4
is direct children of id:3
which is direct children of id:1
.so falls into beauty category.
id:5
has parentCategoryId:4
that means id:5
is direct children of id:4
which is direct children of id:3
which is direct children of id:1
and falls into beauty category.
const categories = [
{id:1,name:'beauty',parentCategoryId:null},
{id:2, name:'health', parentCategoryId:null},
{id:3, name:'hair care', parentCategoryId:1},
{id:4, name:'hair oil', parentCategoryId:3},
{id:5, name:'kumarika hair oil', parentCategoryId:4},
{id:6, name:'supplements', parentCategoryId:2}
]
I have tried recursive function but couldn't find the appropriate output.Say for example I am calling this recursive function with the object that has id:1
.
let newCategoriesArray =[]
const getAllChildCategories = (category) => {
let childCategories = categories.filter(
(cat) => cat.parentCategory == category.id
);
newCategoriesArray.push(...childCategories);
if (childCategories.length > 0) {
childCategories.map((cat) => {
getAllChildCategories(cat);
});
}
};
My expected output should be an array of categories that is direct or nested children of beauty (id:1
).
So the new array should look like this.please take into consideration there may exist more nested categorie.
const newCategoriesArray = [
{id:3, name:'hair care', parentCategoryId:1},
{id:4, name:'hair oil', parentCategoryId:3},
{id:5, name:'kumarika hair oil', parentCategoryId:4},
]
You have some interesting options already, provided categories
isn't a very long list (like thousands of entries). (They do lots of looping through the list.)
If there are a lot of categories in the list (at least thousands), but the hierarchies aren't hundreds deep, I'd probably just loop through categories
once, checking the ancestry of each target category as I went.
I'd start by keeping a map of categories by their ID (just after the categories
array, unless that's dynamic; if it's dynamic, create the map on the fly):
const categoriesById = new Map(
categories.map((category) => [category.id, category])
);
Then get the target category ID (since you seem to be starting with a category object) and an array for the results:
const targetId = category.id;
const results = [];
Then loop through the categories:
for (const cat of categories) {
In the loop, we'll go through cat
's ancestors (if any) seeing if any of them matches the target:
// Start with this category in `c`...
let c = cat;
// While `c` exists and has a parent...
while (c && c.parentCategoryId) {
// Get its parent
c = c.parentCategoryId && categoriesById.get(c.parentCategoryId);
// Does the parent match?
if (c.id === targetId) {
// Found it
results.push(cat);
break;
}
// The loop will continue searching ancestry of `cat` via `c`
}
and that's it!
Working example (rather shorter without the explanatory comments):
const categories = [ { id: 1, name: "beauty", parentCategoryId: null }, { id: 2, name: "health", parentCategoryId: null }, { id: 3, name: "hair care", parentCategoryId: 1 }, { id: 4, name: "hair oil", parentCategoryId: 3 }, { id: 5, name: "kumarika hair oil", parentCategoryId: 4 }, { id: 6, name: "supplements", parentCategoryId: 2 }, ];
const categoriesById = new Map( categories.map((category) => [category.id, category]));
const getAllChildCategories = (category) => {
const targetId = category.id;
const results = [];
for (const cat of categories) {
let c = cat;
while (c && c.parentCategoryId) {
c = c.parentCategoryId && categoriesById.get(c.parentCategoryId);
if (c.id === targetId) {
results.push(cat);
break;
}
}
}
return results;
};
console.log(getAllChildCategories(categories[0]));
.as-console-wrapper {
max-height: 100% !important;
}