I have the JSON received from BE:
[
{
"id": 51,
"name": null,
"parentAccountName": "test-name",
"parentAccountId": 50
},
{
"id": 87,
"name": null,
"parentAccountName": "nam1",
"parentAccountId": 83
},
{
"id": 86,
"name": null,
"parentAccountName": "nam1",
"parentAccountId": 83
},
{
"id": 85,
"name": null,
"parentAccountName": "Test andrei",
"parentAccountId": 37
},
{
"id": 84,
"name": "nam1",
"parentAccountName": "Test andrei",
"parentAccountId": 37
},
{
"id": 50,
"name": "test-name",
"parentAccountName": "nam1",
"parentAccountId": 83
},
{
"id": 37,
"name": "Test andrei",
"parentAccountName": "test-name",
"parentAccountId": 50
},
{
"id": 34,
"name": null,
"parentAccountName": "Test andrei",
"parentAccountId": 37
}
]
I need to create a hierarchy of accounts based on the parentAccountId and the rule is: Check for each entry of the list if has a parent and assign to it, otherwise to create that element as a root one and put it at the right place in the hierarchy. The result should be:
[
{
parentAccountName: 'nam1',
parentAccountId: 83,
children: [
{
id: 50,
name: 'test-name',
parentAccountName: 'nam1',
parentAccountId: 83,
children: [
{
id: 37,
name: 'Test andrei',
parentAccountName: 'test-name',
parentAccountId: 50,
children: [
{
id: 85,
name: null,
parentAccountName: 'Test andrei',
parentAccountId: 37,
},
{
id: 84,
name: 'nam1',
parentAccountName: 'Test andrei',
parentAccountId: 37,
},
{
id: 34,
name: null,
parentAccountName: 'Test andrei',
parentAccountId: 37,
},
],
},
{
id: 51,
name: null,
parentAccountName: 'test-name',
parentAccountId: 50,
},
],
},
{
id: 87,
name: null,
parentAccountName: 'nam1',
parentAccountId: 83,
},
{
id: 86,
name: null,
parentAccountName: 'nam1',
parentAccountId: 83,
},
],
},
];
I tried to do s recursive function and check by parentAcountId, but something I'm doing wrong. Also the format got from BE is not so clear for that. My solution is:
const loadLazyData = (): void => {
if (props.accounts) {
setAccountsHierarchy(configureHierarchyNodes(props.accounts, 0));
}
};
const configureHierarchyNodes = (hierarchy: IAccount[], parent?: number | undefined | null): TreeNode[] => {
const result = [];
for (const i in hierarchy) {
if (hierarchy[i].parentAccountId == parent) {
const children = configureHierarchyNodes(hierarchy, hierarchy[i].id);
if (children.length) {
hierarchy[i].children = children;
}
result.push({ ...hierarchy[i], key: `${i}-${hierarchy[i].id}`, label: hierarchy[i].accountDisplayName });
}
}
return result;
};
Maybe I miss something, but during 2 days I didn't manage to solve this problem. If anybody has any idea, I will be grateful. Thanks in advance!
CodePudding user response:
Reduce the array to a Map, and then convert it back to an array, and use Array.filter()
to get all nodes without a parentAccountId
property. If there should be only a single top level parent, use Array.find()
instead.
const arr = [{"id":51,"name":null,"parentAccountName":"test-name","parentAccountId":50},{"id":87,"name":null,"parentAccountName":"nam1","parentAccountId":83},{"id":86,"name":null,"parentAccountName":"nam1","parentAccountId":83},{"id":85,"name":null,"parentAccountName":"Test andrei","parentAccountId":37},{"id":84,"name":"nam1","parentAccountName":"Test andrei","parentAccountId":37},{"id":50,"name":"test-name","parentAccountName":"nam1","parentAccountId":83},{"id":37,"name":"Test andrei","parentAccountName":"test-name","parentAccountId":50},{"id":34,"name":null,"parentAccountName":"Test andrei","parentAccountId":37}]
const result = Array.from(
arr.reduce((acc, o) => {
const { parentAccountId: id, parentAccountName: name } = o
if(!acc.has(id)) acc.set(id, { id, name }) // if the current item's parent doesn't exist, create it in the Map
const parent = acc.get(id) // get the current parent
parent.children ??= [] // init children if it doesn't exist
if(!acc.has(o.id)) acc.set(o.id, o) // add the current item to the Map if it doesn't exist
else Object.assign(acc.get(o.id), o) // combine it with the existing object if it does
parent.children.push(acc.get(o.id)) // add the item to the children
return acc
}, new Map()).values()
).filter(o => !o.hasOwnProperty('parentAccountId'))
console.log(result)
.as-console-wrapper { max-height: 100% !important; top: 0; }
CodePudding user response:
You could take a standard algorithm for creating a tree.
As result take the parents who have no own object.
const
getTree = (data, id, parent) => {
const
t = {},
parents = new Set,
children = new Set;
data.forEach(o => {
parents.add(o[parent]);
children.add(o[id]);
((t[o[parent]] ??= {}).children ??= []).push(Object.assign(t[o[id]] ??= {}, o))
});
children.forEach(Set.prototype.delete, parents);
return [...parents].flatMap(id => t[id].children);
},
data = [{ id: 51, name: null, parentAccountName: "test-name", parentAccountId: 50 }, { id: 87, name: null, parentAccountName: "nam1", parentAccountId: 83 }, { id: 86, name: null, parentAccountName: "nam1", parentAccountId: 83 }, { id: 85, name: null, parentAccountName: "Test andrei", parentAccountId: 37 }, { id: 84, name: "nam1", parentAccountName: "Test andrei", parentAccountId: 37 }, { id: 50, name: "test-name", parentAccountName: "nam1", parentAccountId: 83 }, { id: 37, name: "Test andrei", parentAccountName: "test-name", parentAccountId: 50 }, { id: 34, name: null, parentAccountName: "Test andrei", parentAccountId: 37 }],
tree = getTree(data, 'id', 'parentAccountId');
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }