'Issue in creating recursive JSON hierarchy tree

I have input data in flatfile format. I have written my javascript code to create recursive hierarchy JSON tree. I am not getting expected tree (highlighted below as expected output). Can anyone please help me understand where I might be going wrong?

Note: In input data if there is no child_id it means it is leaf node.

Input data with code

var data=[
         {"Type":"Root","url":"abc","description":"Enterprise Risk Management Framework","id":0,"child_id":3},

{"Type":"Stem","url":"def","description":"Risk Governance Framework","id":3,"child_id":4},

{"Type":"Stem","url":"def","description":"Risk Governance Framework","id":3,"child_id":9},

{"Type":"Stem","url":"def","description":"Risk Governance Framework","id":3,"child_id":11},

{"Type":"Stem","url":"ghi","description":"Wholesale Credit Risk framework","id":4,"child_id":6},

{"Type":"Stem","url":"jkl","description":"Wholesale Credit Risk Policy","id":6,"child_id":7},

{"Type":"Stem","url":"jkl","description":"Wholesale Credit Risk Policy","id":6,"child_id":8},

{"Type":"Leaf","url":"mno","description":"Wholesale Credit In-Business Quality Assurance Standard","id":7},

{"Type":"Leaf","url":"pqr","description":"WCR Exception Management Standard","id":8},

{"Type":"Stem","url":"stu","description":"Global Collateral Management Policy","id":9,"child_id":10},

{"Type":"Leaf","url":"gov","description":"WCR Collateral Management Standard","id":10},

{"Type":"Stem","url":"iit","description":"Real Estate Appraisal and Valuation Policy","id":11,"child_id":12},

{"Type":"Stem","url":"iim","description":"Commercial Real Estate Appraisal/Valuation Standard","id":12,"child_id":13},

{"Type":"Leaf","url":"har","description":"Commercial Real Estate Appraisal/Valuation Procedures","id":13}
        ]



// Given a parent ID, find and return the item in the data with that ID
const findParent = parentId => data.find(item => item.child_id === parentId)

// Create the tree by reducing the data to a root list
// that only contains "orphans". Items that do have a
// parent will be appended to those orphans' child lists
// instead
const tree = data.reduce((root, item) => {
  // Find the parent of the current item
  const parent = findParent(item.id)

  if (parent) {
    // If a parent was found, append the current item
    // to the parent's child list. Since objects are
    // passed by reference, it doesn't matter whether 
    // the parent is already in the root list  or not 
    // -- it always points to the same object
    parent.children = parent.children || []
    parent.children.push(item)
  } else {
    // Otherwise push the item to the root list
    root.push(item)
  }

  return root
}, [])

console.log(JSON.stringify(tree));

Current Output

[
  {
    "Type": "Root",
    "url": "abc",
    "description": "Enterprise Risk Management Framework",
    "id": 0,
    "child_id": 3,
    "children": [
      {
        "Type": "Stem",
        "url": "def",
        "description": "Risk Governance Framework",
        "id": 3,
        "child_id": 4,
        "children": [
          {
            "Type": "Stem",
            "url": "mno",
            "description": "Wholesale Credit Risk Framework",
            "id": 4,
            "child_id": 6,
            "children": [
              {
                "Type": "Stem",
                "url": "pqr",
                "description": "Wholesale Credit Risk Policy",
                "id": 6,
                "child_id": 7,
                "children": [
                  {
                    "Type": "Leaf",
                    "url": "vwx",
                    "description": "Wholesale Credit In-Business Quality Assurance Standard",
                    "id": 7
                  }
                ]
              },
              {
                "Type": "Stem",
                "url": "stu",
                "description": "Wholesale Credit Risk Policy",
                "id": 6,
                "child_id": 8,
                "children": [
                  {
                    "Type": "Leaf",
                    "url": "zab",
                    "description": "WCR Exception Management Standard",
                    "id": 8
                  }
                ]
              }
            ]
          }
        ]
      },
      {
        "Type": "Stem",
        "url": "ghi",
        "description": "Risk Governance Framework",
        "id": 3,
        "child_id": 9,
        "children": [
          {
            "Type": "Stem",
            "url": "nsr",
            "description": "Global Collateral Management Policy",
            "id": 9,
            "child_id": 10,
            "children": [
              {
                "Type": "Leaf",
                "url": "gov",
                "description": "WCR Collateral Management Standard",
                "id": 10
              }
            ]
          }
        ]
      },
      {
        "Type": "Stem",
        "url": "jkl",
        "description": "Risk Governance Framework",
        "id": 3,
        "child_id": 11,
        "children": [
          {
            "Type": "Stem",
            "url": "iit",
            "description": "Real Estate Appraisal and Valuation Policy",
            "id": 11,
            "child_id": 12,
            "children": [
              {
                "Type": "Stem",
                "url": "iim",
                "description": "Commercial Real Estate Appraisal/Valuation Standard",
                "id": 12,
                "child_id": 13,
                "children": [
                  {
                    "Type": "Leaf",
                    "url": "har",
                    "description": "Commercial Real Estate Appraisal/Valuation Procedures",
                    "id": 13
                  }
                ]
              }
            ]
          }
        ]
      }
    ]
  }
]

expected Output

{
  "id": 0,
  "type": "Root",
  "description": "Enterprise Risk Management Framework",
  "url": "abc",
  "children": [
    {
      "id": 3,
      "type": "Stem",
      "description": "Risk Governance Framework",
      "url": "def",
      "children": [
        {
          "id": 4,
          "type": "Stem",
          "description": "Wholesale Credit Risk Framework",
          "url": "ghi",
          "children": [
            {
              "id": 6,
              "type": "Stem",
              "description": "Wholesale Credit Risk Policy",
              "url": "jkl",
              "children": [
                {
                  "id": 7,
                  "type": "Leaf",
                  "description": "Wholesale Credit In-Business Quality Assurance Standard",
                  "url": "mno",
                  "children": [
                    
                  ]
                },
                {
                  "id": 8,
                  "type": "Leaf",
                  "description": "WCR Exception Management Standard",
                  "url": "pqr",
                  "children": [
                    
                  ]
                }
              ]
            }
          ]
        },
        {
          "id": 9,
          "type": "Stem",
          "description": "Global Collateral Management Policy",
          "url": "stu",
          "children": [
            {
              "id": 10,
              "type": "Leaf",
              "description": "WCR Collateral Management Standard",
              "url": "gov",
              "children": [
                
              ]
            }
          ]
        },
        {
          "id": 11,
          "type": "Stem",
          "description": "Real Estate Appraisal and Valuation Policy",
          "url": "iit",
          "children": [
            {
              "id": 12,
              "type": "Stem",
              "description": "Commercial Real Estate Appraisal/Valuation Standard",
              "url": "iim",
              "children": [
                {
                  "id": 13,
                  "type": "Leaf",
                  "description": "Commercial Real Estate Appraisal/Valuation Procedures",
                  "url": "har",
                  "children": [
                    
                  ]
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}


Solution 1:[1]

Here's an example based on this answer. I have refactored your data to use id/parentId. I have removed the duplicates/not duplicates (you only really need 1 thing in the dataset per element of the tree, no matter how many children it has).

var data=[
  {"Type":"Root","url":"abc","description":"Enterprise Risk Management Framework","id":0},
  {"Type":"Stem","url":"def","description":"Risk Governance Framework","id":3, "parentId": 0},
  {"Type":"Stem","url":"ghi","description":"Wholesale Credit Risk framework","id":4, "parentId": 3},
  {"Type":"Stem","url":"jkl","description":"Wholesale Credit Risk Policy","id":6, "parentId": 4},
  {"Type":"Leaf","url":"mno","description":"Wholesale Credit In-Business Quality Assurance Standard","id":7, "parentId": 6},
  {"Type":"Leaf","url":"pqr","description":"WCR Exception Management Standard","id":8, "parentId": 6},
  {"Type":"Stem","url":"stu","description":"Global Collateral Management Policy","id":9, "parentId": 3},
  {"Type":"Leaf","url":"gov","description":"WCR Collateral Management Standard","id":10, "parentId": 9},
  {"Type":"Stem","url":"iit","description":"Real Estate Appraisal and Valuation Policy","id":11, "parentId": 3},
  {"Type":"Stem","url":"iim","description":"Commercial Real Estate Appraisal/Valuation Standard","id":12,"parentId":11},
  {"Type":"Leaf","url":"har","description":"Commercial Real Estate Appraisal/Valuation Procedures","id":13, "parentId": 12}
];
        
        
const createDataTree = dataset => {
  const map = {};
  dataset.forEach(aData => map[aData.id] = aData);
  const dataTree = [];
  dataset.forEach(d => {
    if (d.parentId !== undefined) {
      map[d.parentId].children = map[d.parentId].children || [];
      map[d.parentId].children.push(map[d.id]);
    } else {
      dataTree.push(map[d.id]);
    }
  });
  return dataTree;
};

const tree = createDataTree(data);
console.log(tree);

Solution 2:[2]

You could collect the id and corresponding target object in a Map. Initially the children property of each object will be empty. Then iterate the data again to lookup the object for a given id and the object for the given child_id and put the latter object into the children array of the former. Finally, get the root object which is assumed to have id 0.

Code:

const data = [{"Type":"Root","url":"abc","description":"Enterprise Risk Management Framework","id":0,"child_id":3},{"Type":"Stem","url":"def","description":"Risk Governance Framework","id":3,"child_id":4},{"Type":"Stem","url":"def","description":"Risk Governance Framework","id":3,"child_id":9},{"Type":"Stem","url":"def","description":"Risk Governance Framework","id":3,"child_id":11},{"Type":"Stem","url":"ghi","description":"Wholesale Credit Risk framework","id":4,"child_id":6},{"Type":"Stem","url":"jkl","description":"Wholesale Credit Risk Policy","id":6,"child_id":7},{"Type":"Stem","url":"jkl","description":"Wholesale Credit Risk Policy","id":6,"child_id":8},{"Type":"Leaf","url":"mno","description":"Wholesale Credit In-Business Quality Assurance Standard","id":7},{"Type":"Leaf","url":"pqr","description":"WCR Exception Management Standard","id":8},{"Type":"Stem","url":"stu","description":"Global Collateral Management Policy","id":9,"child_id":10},{"Type":"Leaf","url":"gov","description":"WCR Collateral Management Standard","id":10},{"Type":"Stem","url":"iit","description":"Real Estate Appraisal and Valuation Policy","id":11,"child_id":12},{"Type":"Stem","url":"iim","description":"Commercial Real Estate Appraisal/Valuation Standard","id":12,"child_id":13},{"Type":"Leaf","url":"har","description":"Commercial Real Estate Appraisal/Valuation Procedures","id":13}];

const map = new Map(data.map(({child_id, ...rest}) => [rest.id, {...rest, children: []}]));

for (const {id, child_id} of data) {
    if (!child_id) continue;
    const child = map.get(child_id);
    child.parentId = id;
    map.get(id).children.push(child);
}

console.log(map.get(0));

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 James
Solution 2