Search code examples
javascripttypescripttreetreenodetreetable

Object to Tree for TreeTable, group by twice Typescript / JavaScript


I am trying to convert a list into a tree structure for a primeng TreeTable.

[{pk:"1", corpID:"1234", date: "31/03/21", rela:"4325", price:"20.00"},
{pk:"2", corpID:"1234", date: "21/03/21", rela:"4425", price:"50.00"} ,
{pk:"3", corpID:"3456", date: "03/03/21", rela:"6327", price:"80.00"} ,
{pk:"4", corpID:"4567", date: "05/03/21", rela:"7328", price:"40.00"}]

I need to group the data twice, first by corpId and second by rela. PrimeNG TreeTable uses data and children- the data will be the value shown on the row and the children will be the data in the expanded row. https://www.primefaces.org/primeng/showcase/#/treetable The structure should be :

{ data : [
    
        { 
            data: {
                corpID : "1234"
                },
                children: [
                   {
                   data:{ 
                     RELA: "4325"
                },
                children: [
                        {
                        data : { pk:"1",
                                 corpID:"1234",
                                 date: "31/03/21", 
                                 rela:"4325",
                                 price:"20.00"},
                        }]
                 },
                data:{ 
                   RELA: "4425"
                },
                children: [
                        {
                               { pk:"2", 
                                 corpID:"2345",
                                 date: "21/03/21",
                                 rela:"4425", 
                                 price:"50.00"
                         }
                       ]
...

I have tried grouping by and a function using reduce, although it created the correct tree structure, it condensed the data. Is there a way to build the tree structure while also including the data and children attributes? Any help would be greatly appreciated! The function I tried below reduced the data also I wasn't sure how to add in the data and children

  let result  = this.data.reduce(this.totree, {}); 

 totree(branches, node) {

    if (!branches[node.corpId]) {
      branches[node.corpId] = {};
    }
    branches[node.corpId][node.rela] = node;
    branches[node.corpId][node.rela] = Object.assign(branches[node.corpId][node.rela]);
    return branches;
  }

Solution

  • I just wrote and tested this code for you, I believe it can be better refactored but most important that it can achieve the same structure you wanted

    const arr = [
      { pk: "1", corpID: "1234", date: "31/03/21", rela: "4325", price: "20.00" },
      { pk: "2", corpID: "1234", date: "21/03/21", rela: "4425", price: "50.00" },
      { pk: "3", corpID: "3456", date: "03/03/21", rela: "6327", price: "80.00" },
      { pk: "4", corpID: "4567", date: "05/03/21", rela: "7328", price: "40.00" },
    ];
    
    const groupBy = (arrayInput, key) => {
      return arrayInput.reduce(
        (r, v, i, a, k = v[key]) => ((r[k] || (r[k] = [])).push(v), r),
        {}
      );
    };
    
    const groupedByCorpID = groupBy(arr, "corpID");
    
    const ans = Object.entries(groupedByCorpID).map(([key, value]) => {
      const groupedByRela = groupBy(value, "rela");
    
      const children = Object.entries(groupedByRela).map(
        ([childKey, childValue]) => {
          return {
            data: { RELA: childKey },
            children: childValue,
          };
        }
      );
    
      return { data: { corpID: key }, children };
    });