javascriptarraysjsonmongodblodash

Flattening hierarchical json data for table display


this is the basic structure of tree:

{ 
    "DescId" : "1", 
    "Desc" : "Parent 1", 
    "ParentId" : "null", 
    "Order" : 1.0, 
    "Type" : "A", 
    "Parent" : null, 
    "Depth" : 0.0
}
{ 
    "DescId" : "1.1", 
    "Desc" : "Child 1", 
    "ParentId" : "1", 
    "Order" : 1.0, 
    "Type" : "B", 
    "Parent" : "Parent 1", 
    "Depth" : 1.0
}
{ 
    "DescId" : "1.2", 
    "Desc" : "Child 2", 
    "ParentId" : "1", 
    "Order" : 2.0, 
    "Type" : "B", 
    "Parent" : "Parent 1", 
    "Depth" : 1.0
}
{ 
    "DescId" : "1.1.1", 
    "Desc" : "Grand Child 1", 
    "ParentId" : "1.1", 
    "Order" : 1.0, 
    "Type" : "C", 
    "Parent" : "Child 1", 
    "Depth" : 2.0
}
{ 

    "DescId" : "1.1.1.1", 
    "Desc" : "Great Grand Child 1", 
    "ParentId" : "1.1.1", 
    "Order" : 1.0, 
    "Type" : "D", 
    "Parent" : "Grand Child 1", 
    "Depth" : 3.0
}
{ 

    "DescId" : "2", 
    "Desc" : "Parent 2", 
    "ParentId" : null, 
    "Order" : 2.0, 
    "Type" : "A", 
    "Parent" : null, 
    "Depth" : 0.0
}

I have this hierarchical json data as below:

[
  {
    "DescId": "1",
    "Desc": "Parent 1",
    "Type": "A",
    "children": [
      {
        "DescId": "1.2",
        "Desc": "Child 2",
        "ParentId": "1",
        "Order": 2,
        "Type": "B",
        "Parent": "Parent 1",
        "Depth": 1
      },
      {
        "DescId": "1.1",
        "Desc": "Child 1",
        "ParentId": "1",
        "Order": 1,
        "Type": "B",
        "Parent": "Parent 1",
        "Depth": 1
      }
    ]
  },
  {
    "DescId": "1.1",
    "Desc": "Child 1",
    "Type": "B",
    "children": [
      {
        "DescId": "1.1.1",
        "Desc": "Grand Child 1",
        "ParentId": "1.1",
        "Order": 1,
        "Type": "C",
        "Parent": "Child 1",
        "Depth": 2
      }
    ]
  },
  {
    "DescId": "1.2",
    "Desc": "Child 2",
    "Type": "B",
    "children": []
  },
  {
    "DescId": "1.1.1",
    "Desc": "Grand Child 1",
    "Type": "Consequence",
    "children": [
      {
        "DescId": "1.1.1.1",
        "Desc": "Great Grand Child 1",
        "ParentId": "1.1.1",
        "Order": 1.0,
        "Type": "D",
        "Parent": "Grand Child 1",
        "Depth": 3.0
      }
    ]
  },
  {
    "DescId": "1.1.1.1",
    "Desc": "Great Grand Child 1",
    "Type": "D",
    "children": []
  },
  {
    "DescId": "2",
    "Desc": "Parent 2",
    "Type": "A",
    "children": []
  }
]

I have this requirement where I need to display this hierarchical tree as a tabular structure.

So data needs to be like below:

[
  {
    "A" + "DescId" : "1",
    "A" + "Desc" : "Parent",
    "B" + "DescId" : "1.1",
    "B" + "Desc" : "Child 1,
    "C" + "DescId" : "1.1.1",
    "C" + "Desc" : "Grand Child 1"
    "D" + "DescId" : "1.1.1.1",
    "D" + "Desc" : "Great Grand child 1"
  },
  {
    "A" + "DescId" : "1",
    "A" + "Desc" : "Parent 1",
    "B" + "DescId" : "1.2"
    "B" + "Desc" : "Child 2
    //if there are any further generations like 1.2.1 or 1.2.1.1 should be present here
  },
  {
    "A" + "DescId" : "2",
    "A" + "Desc" : "Parent 2"
  }
]

I have tried this code below in javascript and lodash:

function reformatData(sentData) {
        var finalData = {};
        var returnArray = [];
        if (sentData.length > 0) {
            var propertyNameArray = Object.keys(sentData[0]);

            for (var i = 0; i < sentData.length; i++) {
                var type = sentData[i].Type;
                finalData[type + propertyNameArray[0]] = sentData[i].DescId;
                finalData[type + propertyNameArray[1]] = sentData[i].Desc;
                if (sentData[i].children && sentData[i].children.length > 0) {
                    var children = _.orderBy(sentData[i].children, ['Order'], ['asc']);
                    reformatData(children);
                }
            }
        }
        returnArray.push(finalData);
        return returnArray;
    }

The above code is ignoring first parent and adding only next available one. Could anyone help me pointing out what I am missing here. Below is the output code is generating:

[
  {
    "ADescid":"2",
    "ADesc":"Parent 2",
    "BDescid":"1.2",
    "BDesc":"Child 2",
    "CDescid":"1.1.1",
    "CDesc":"Grand Child 1",
    "DDescid":"1.1.1.1",
    "DDesc":"Great grand child 1"
  }
]

Solution

  • This proposal works in three steps:

    1. Build the tree.
    2. Collect all nodes to the final leaves.
    3. Generate single objects with wanted keys as final result.

    function getTree(array, root) {
        var o = {};
        array.forEach(function (a) {
            o[a.DescId] = Object.assign({}, a, o[a.DescId]);
            o[a.ParentId] = o[a.ParentId] || {};
            o[a.ParentId].children = o[a.ParentId].children || [];
            o[a.ParentId].children.push(o[a.DescId]);
        });
        return o[root].children;
    }
    
    function getLeafes(tree) {
        var result = [];
        tree.forEach(function iter(temp) {
            return function ({ DescId, Desc, Type, children }) {
                var t = temp.concat({ DescId, Desc, Type });
                if (!children) {
                    result.push(t);
                    return;
                }
                children.forEach(iter(t));
            };
        }([]));
        return result;
    }
    
    var nodes = [{ DescId: "1", Desc: "Parent 1", ParentId: "null", Order: 1, Type: "A", Parent: null, Depth: 0 }, { DescId: "1.1", Desc: "Child 1", ParentId: "1", Order: 1, Type: "B", Parent: "Parent 1", Depth: 1 }, { DescId: "1.2", Desc: "Child 2", ParentId: "1", Order: 2, Type: "B", Parent: "Parent 1", Depth: 1 }, { DescId: "1.1.1", Desc: "Grand Child 1", ParentId: "1.1", Order: 1, Type: "C", Parent: "Child 1", Depth: 2 }, { DescId: "1.1.1.1", Desc: "Great Grand Child 1", ParentId: "1.1.1", Order: 1, Type: "D", Parent: "Grand Child 1", Depth: 3 }, { DescId: "2", Desc: "Parent 2", ParentId: null, Order: 2, Type: "A", Parent: null, Depth: 0 }],
        tree = getTree(nodes, null),
        leaves = getLeafes(tree),
        result = leaves.map(a => a.reduce((o, { DescId, Desc, Type }) => Object.assign(o, { [Type + 'DescId']: DescId, [Type + 'Desc']: Desc }), {}));
    
    console.log(tree);
    console.log(leaves);
    console.log(result);
    .as-console-wrapper { max-height: 100% !important; top: 0; }