Creating nested json object based on given condition

Dungeon :

I have a flat list (array of objects), like next one:

var myList = [
  {id:1, name:"ABC", type:"level_1"},
  {id:2, name:"XYZ", type:"level_1"},
  {id:1, name:"ABC_level 2", type:"level_2", level_one_id:1},
  {id:2, name:"XYZ_level 2", type:"level_2", level_one_id:2},
  {id:1, name:"ABC_level 3", type:"level_3", level_two_id:1},
  {id:2, name:"XYZ_level 3", type:"level_3", level_two_id:2},
];

Then, I have to group them in such a way that I can create a hierarchy of levels (which I tried to do in the below lines of code):

var myList = [
  {id:1, name:"ABC", type:"level_1"},
  {id:2, name:"XYZ", type:"level_1"},
  {id:1, name:"ABC_level 2", type:"level_2", level_one_id:1},
  {id:2, name:"XYZ_level 2", type:"level_2", level_one_id:2},
  {id:1, name:"ABC_level 3", type:"level_3", level_two_id:1},
  {id:2, name:"XYZ_level 3", type:"level_3", level_two_id:2},
];

var myNestedList = {
    levels: []
};
    
//-----------pushing level1----------

myList.forEach((res => {
    if (res.type == "level_1") {
        myNestedList.levels.push(res);
    }
}));

//-----------pushing level 2---------

myNestedList.levels.forEach((res) => {
    myList.forEach((val) => {
        if (val.type == "level_2" && val.level_one_id == res.id) {
            res["level_2"] = [] || res["level_2"];
            res["level_2"].push(val);
        }
    })
})
    
//-----------pushing level 3---------
    
myNestedList.levels.forEach((res) => {
    res["level_2"].forEach((val) => {
        myList.forEach((lastlevel) => {
            if (lastlevel.type == "level_3" && lastlevel.level_two_id == val.id) {
                val["level_3"] = [] || val["level_3"];
                val["level_3"].push(lastlevel);
            }
        })
    })
})

console.log(myNestedList);

Although I'm able to achieve the result, I'm sure this code can be more precise and meaningful. Can we make use of lodash here and get this code shorter?

Any help would be much appreciated. Thanks!

Nina Scholz :

You could take a virtual unique id for the object and for referencing the parents and collect the items in a tree.

This approach works with unsorted data as well.

var data = [{ id: 1, name: "ABC", type: "level_1" }, { id: 2, name: "XYZ", type: "level_1" }, { id: 1, name: "ABC_level 2", type: "level_2", level_one_id: 1 }, { id: 2, name: "XYZ_level 2", type: "level_2", level_one_id: 2 }, { id: 1, name: "ABC_level 3", type: "level_3", level_two_id: 1 }, { id: 2, name: "XYZ_level 3", type: "level_3", level_two_id: 2 }],
    tree = function (data) {
        var t = {};
        data.forEach(o => {
            var level = o.type.match(/\d+$/)[0],
                parent = o[Object.keys(o).filter(k => k.startsWith('level_'))[0]] || 0,
                parentId = `${level - 1}.${parent}`,
                id = `${level}.${o.id}`,
                children = `level_${level}`;

            Object.assign(t[id] = t[id] || {}, o);
            t[parentId] = t[parentId] || {};
            t[parentId][children] = t[parentId][children] || [];
            t[parentId][children].push(t[id]);
        });
        return t['0.0'].level_1;
    }(data);

console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=34393&siteId=1