Home > Software engineering >  Create a hierarchy list from an JSON based on some key values JavaScript
Create a hierarchy list from an JSON based on some key values JavaScript

Time:03-08

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; }

  • Related