Skip to content

transfer flat object to nested object (javascript)

i am getting a flat object of cms navigation and want to transfer it to a nested object.
The level describes the position of the element in the tree.
Whenever there are subelements they should be stored under a new subCategory.
In every level could be multiple elements.
For example two level 1 categories (“shop service” and “information”).

The flat object:

[
    {
        "categoryId": "2002",
        "level": "1",
        "name": "Shop Service"
    },
    {
        "categoryId": "2504",
        "level": "2",
        "name": "Neukunde werden"
    },
    {
        "categoryId": "3501",
        "level": "3",
        "name": "Ebene 3"
    },
    {
        "categoryId": "3503",
        "level": "4",
        "name": "Ebene 4"
    },
    {
        "categoryId": "1009",
        "level": "2",
        "name": "Projektanfrage"
    },
    {
        "categoryId": "1008",
        "level": "2",
        "name": "Kontakt"
    },
    {
        "categoryId": "3502",
        "level": "3",
        "name": "Ebene 3"
    },
    {
        "categoryId": "1019",
        "level": "1",
        "name": "Information"
    },
    {
        "categoryId": "1007",
        "level": "2",
        "name": "Impressum"
    }
]

The result should be a nested object with this structure

[
    {
      categoryId: '2002',
      level: '1',
      name: 'Shop Service',
      subCategory: [
        {
          categoryId: '2504',
          level: '2',
          name: 'Neukunde werden',
          subCategory: {
            categoryId: '3501',
            level: '3',
            name: 'Ebene 3',
            subCategory: { categoryId: '3503', level: '4', name: 'Ebene 4' },
          },
        },
        { categoryId: '1009', level: '2', name: 'Projektanfrage' },
        {
          categoryId: '1008',
          level: '2',
          name: 'Kontakt',
          subCategory: {
            categoryId: '3502',
            level: '3',
            name: 'Ebene 3',
          },
        },
      ],
    },
    { categoryId: '1019', level: '1', name: 'Information' },
  ]

I tried serveral ways, but can’t make it.

Thanks in advance.
Stefan

Answer

You can use a stack to track where you are in the tree while it is being constructed.

It is strange that level has a string data type while clearly its meaning is numeric.

const data = [{"categoryId": "2002","level": "1","name": "Shop Service"},{"categoryId": "2504","level": "2","name": "Neukunde werden"},{"categoryId": "3501","level": "3","name": "Ebene 3"},{"categoryId": "3503","level": "4","name": "Ebene 4"},{"categoryId": "1009","level": "2","name": "Projektanfrage"},{"categoryId": "1008","level": "2","name": "Kontakt"},{"categoryId": "3502","level": "3","name": "Ebene 3"},{"categoryId": "1019","level": "1","name": "Information"},{"categoryId": "1007","level": "2","name": "Impressum"}];

let hierarchy = []; // The final result -- will be populated below
let path = [hierarchy]; // A stack
for (let obj of data) {
    if (+obj.level < path.length) path.length = obj.level;
    if (+obj.level === path.length) {
        path.at(-1).push(obj);
    } else if (+obj.level === path.length + 1) {
        path.push(path.at(-1).at(-1).subCategory = [obj]);
    } else throw "Unexpected level increase";
}

console.log(hierarchy);