I assume you get the data from some site with this structure already define and this cannot be changed. Another way I suggest you to change the structure you're getting to something more manageable.
Anyway, following your structure or not, when you need to build a tree you must work recursively, to get the deepest structure and define correctly what you need.
Keep in mind this:
- In your structure, you only have a subcategory per item but you can have a lot of entries with the same parent category where the only change is the subcategory element, this is not too optimal.
- Since the structure becomes already defined, I think is better to treat and reorder it before arming the tree structure
- To get a full example, I modified your data structure adding two children elements, because some of "subcategories" you have does not appear there.
So, the structure I used was :
var data1 = [
{
category: 'Techonology',
subcategory: 'laptop',
sale: 19000,
profit: 909049,
},
{
category: 'badge',
sale: 19000,
profit: 909049,
},
{
category: 'childrenchair',
sale: 19000,
profit: 909049,
},
{
category: 'chair',
subcategory: 'childrenchair',
sale: 19000,
profit: 909049,
},
{
category: 'Furniture',
subcategory: 'badge',
sale: 2009900,
profit: 699600,
},
{
category: 'Techonology',
subcategory: 'chair',
sale: 30000,
profit: 500,
},
{
category: 'Furniture',
subcategory: 'bed',
sale: 400,
profit: 200000,
},
]
and the code below defines the tree structure:
// loops the data to get all subcategory elements, this is used to
// avoid unnecessary iterations.
allChildren = data1.map(item=> item.subcategory).filter(item => !!item);
// this map has the data with the structure we need
preparedData = new Map()
data1.forEach(item => {
console.log(1, item.category, item.subcategory);
const data = preparedData.get(item.category) ?? {children: []};
data.isChildren = allChildren.includes(item.category);
if(item.subcategory) data.children.push(item.subcategory);
preparedData.set(item.category, Object.assign(item, data));
});
tree = [];
/**
getChildren method is recursive, it will be called for each category or subcategory with children's (recursively)
*/
getChildren = item=> {
const children = item.children.filter(item=> {
if(!preparedData.has(item)) return;
const data = preparedData.get(item);
const {category: name, sale, profit} = data;
subchildren = data.children.length ? getChildren(item) : [];
return {name, sale, profit, children: subchildren};
});
return children;
};
// loop the data
preparedData.forEach(item=>{
// it the item has the property isChildren as true, then is a subcategory and
// is not necessary to check it in the first level of the tree
if(item.isChildren) return;
const {category: name, sale, profit} = item;
children = item.children.length ? getChildren(item) : [];
tree.push({name, sale, profit, children});
});
I checked this code in the devtools console and runs, you can copy and pasted it to check and then make the adjusts required