0

Hi i want to get children tree from a category list.

here is my input data

[
  { "parent_id": -1, "name": "Toothpaste", "id": 99 },
   {
        "parent_id": -1,
        "name": "Cake",
        "id": 3
    },
    {
        "parent_id": 3,
        "name": "Chocolate  Cake",
        "id": 4
    },
    {
        "parent_id": 3,
        "name": "Walnut Cake",
        "id": 5
    },
    {
        "parent_id": 4,
        "name": "Chocolate Cake mixin 1",
        "id": 6
    }
]

my desired output will look like below one

[ { "parent_id": -1, "name": "Toothpaste", "id": 99 },
   {
    "parent_id": -1,
    "name": "Cake",
    "id": 3,
    "children":[
        {
            "parent_id": 3,
            "name": "Chocolate  Cake",
            "id": 4,
            "children":[     //<--- observe this one not there in my output 
                {
                    "parent_id": 4,
                    "name": "Chocolate Cake mixin 1",
                    "id": 6
                }
            ]
        },
        {
            "parent_id": 3,
            "name": "Walnut Cake",
            "id": 5
        }
    ],
  }

]

The problem i'm facing is that i'm unable to push data into 2nd level i,e chocolate cake is having children but i'm unable to push that into chocolate cake children

Note: solution must work for any level of nesting

here is what i have tried

function getChildrenTree(childList){
        let childMap = {};
        for(let i = 0; i < childList.length; i++){
           if(childList[i].parent_id === -1)
              childMap[childList[i].id] = {name:childList[i].name,children:[]};
          
        }
    
        for(let i = 0; i < childList.length; i++){
            if(childMap && childMap.hasOwnProperty(childList[i].parent_id) && childMap[childList[i].parent_id].hasOwnProperty('children')) childMap[childList[i].parent_id].children.push(childList[i]);
        }
         
       return Object.values(childMap);
    }

getChildrenTree([ { "parent_id": -1, "name": "Toothpaste", "id": 99 },{ "parent_id": -1, "name": "Cake", "id": 3 }, { "parent_id": 3, "name": "Chocolate  Cake", "id": 4 }, { "parent_id": 3, "name": "Walnut Cake", "id": 5 }, { "parent_id": 4, "name": "Chocolate Cake mixin 1", "id": 6 } ])
EaBengaluru
  • 131
  • 2
  • 17
  • 59
  • Does this answer your question? [Build tree array from flat array in javascript](https://stackoverflow.com/questions/18017869/build-tree-array-from-flat-array-in-javascript) – James Oct 20 '21 at 18:44
  • Not because in my case I can have multiple first level parent with `parent_id = -1` – EaBengaluru Oct 20 '21 at 18:47
  • In my code snippet `toothpaste` is one of the first level parent – EaBengaluru Oct 20 '21 at 18:48
  • @James in my case first level parent will always will be having `id=-1` otherwise it is not a parent. in above comment i have made a mistake instead of `id` i put `parent_id`. – EaBengaluru Oct 20 '21 at 18:54

2 Answers2

2

Here's an approach you can try.

const flat = [
  { "parent_id": -1, "name": "Toothpaste", "id": 99 },
   {
        "parent_id": -1,
        "name": "Cake",
        "id": 3
    },
    {
        "parent_id": 3,
        "name": "Chocolate  Cake",
        "id": 4
    },
    {
        "parent_id": 3,
        "name": "Walnut Cake",
        "id": 5
    },
    {
        "parent_id": 4,
        "name": "Chocolate Cake mixin 1",
        "id": 6
    }
];

const makeTree = (arr, parent) => {
  const branch = arr.filter(node => node.parent_id === parent);
  branch.forEach(node => {
    const children = makeTree(arr, node.id);
    if (children.length) {
      node.children = children;
    }
  });
  return branch;
};

const tree = makeTree(flat, -1);

console.log(tree);
James
  • 20,957
  • 5
  • 26
  • 41
1

You could take a single loop and and object for collecting the nodes and return a tree by taking all children from the root node.

const
    buildTree = (data, root) => {
        var t = {};
        data.forEach(o => {
            Object.assign(t[o.id] = t[o.id] || {}, o);
            ((t[o.parent_id] ??= {}).children ??= []).push(t[o.id]);
        });
        return t[root].children
    },
    data = [{ parent_id: -1, name: "Toothpaste", id: 99 }, { parent_id: -1, name: "Cake", id: 3 }, { parent_id: 3, name: "Chocolate  Cake", id: 4 }, { parent_id: 3, name: "Walnut Cake", id: 5 }, { parent_id: 4, name: "Chocolate Cake mixin 1", id: 6 }],
    tree = buildTree(data, -1);


console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • great solution !! but understanding code is not our level i guess, its very high level. could you please explain these 2 lines `Object.assign(t[o.id] = t[o.id] || {}, { ...o }); ((t[o.parent_id] ??= {}).children ??= []).push(t[o.id]);` – EaBengaluru Oct 21 '21 at 03:22
  • it basically takes `id` as key as reference to the object `t` and the parent `parent_id` as well for paren. but for parent it created maybe unseen `id` object and adds the children inside. this is later the reference for using the root `parent_id` of `-1` to get the complete tree. for example build a tree of only one random node and have a look to `t`. basically it creates always two references, one for the parent relation and another for the children relation in a single loop. – Nina Scholz Oct 21 '21 at 08:00