2

I have a list of objects with parent keys that describes several levels of nested parent / child relationships.

const table =[
    {
        "id": 791,
        "sortOrder": 0,
        "parentCategoryId": 833
    },
    {
        "id": 790,
        "sortOrder": 0,
        "parentCategoryId": 833
    },
    {
        "id": 845,
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {   
        "id": 844,
        "sortOrder": 0,
        "parentCategoryId": 842
    },
    {   
        "id": 802,
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {   
        "id": 788,
        "sortOrder": 0,
        "parentCategoryId": 833
    },
    {    
        "id": 863,
        "sortOrder": 0,
        "parentCategoryId": 863
    },
    {    
        "id": 858,
        "sortOrder": 0,
        "parentCategoryId": 858
    },
    {    
        "id": 867,
        "sortOrder": 0,
        "parentCategoryId": 867
    },
    {    
        "id": 871,
        "sortOrder": 0,
        "parentCategoryId": 867
    },
    {    
        "id": 801,
        "name": "Tickets",
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {    
        "id": 792,
        "sortOrder": 0,
        "parentCategoryId": 833
    },
    {    
        "id": 797,
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {    
        "id": 789,
        "name": "Hot food",
        "sortOrder": 0,
        "parentCategoryId": 833
    },
    {    
        "id": 798,
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {    
        "id": 671,
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {    
        "id": 833,
        "sortOrder": 0,
        "parentCategoryId": 833
    },
    {    
        "id": 796,
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {    
        "id": 843,
        "sortOrder": 0,
        "parentCategoryId": 842
    },
    {    
        "id": 840,
        "sortOrder": 0,
        "parentCategoryId": 793
    },
    {    
        "id": 868,
        "sortOrder": 0,
        "parentCategoryId": 868
    },
    {    
        "id": 851,
        "sortOrder": 0,
        "parentCategoryId": 851
    },
    {    
        "id": 839,
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {    
        "id": 793,
        "sortOrder": 0,
        "parentCategoryId": 839
    },
    {    
        "id": 859,
        "sortOrder": 0,
        "parentCategoryId": 859
    },
    {   
        "id": 805,
        "sortOrder": 0,
        "parentCategoryId": 859
    },
    {    
        "id": 856,
        "name": "DRINKS",
        "sortOrder": 0,
        "parentCategoryId": 805
    },
    {    
        "id": 870,
        "sortOrder": 0,
        "parentCategoryId": 856
    },
    {    
        "id": 787,
        "sortOrder": 0,
        "parentCategoryId": 833
    },
    {    
        "id": 786,
        "sortOrder": 0,
        "parentCategoryId": 833
    },
    {    
        "id": 799,
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {    
        "id": 852,
        "sortOrder": 0,
        "parentCategoryId": 852
    },
    {    
        "id": 795,
        "name": "Gents fragrance",
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {    
        "id": 864,
        "sortOrder": 0,
        "parentCategoryId": 864
    },
    {   
        "id": 854,
        "sortOrder": 0,
        "parentCategoryId": 854
    },
    {    
        "id": 865,
        "sortOrder": 0,
        "parentCategoryId": 865
    },
    {    
        "id": 869,
        "name": "GFI",
        "sortOrder": 0,
        "parentCategoryId": 869
    },
    {    
        "id": 785,
        "sortOrder": 0,
        "parentCategoryId": 833
    }
]

The issue is I don't have a root parent id with 0. I would like to order this in one array that shows in first level items where the id matches parentCategoryId, what means they are each a root and than each of them to have children within children.

Here is how far I got, but struggle to get this right:

var root = { cid: 0, parent_id: null, children: []};
var node_list = { 0 : root};

     for (var i = 0; i < table.length; i++) {

       console.log('updated list', node_list)
       console.log('item in cat', table[i])

       // check if parent ID exsits in the list
       if (!node_list[table[i].parentCategoryId]) {

         console.log('not in the list');
         console.log('node_list[table[i].parentCategoryId]', table[i].parentCategoryId)
         if (table[i].parentCategoryId === table[i].cid) {
           console.log('it is the root');
           node_list[table[i].cid] = table[i];
         }    

       } else {

         const item = table[i];
         console.log('item is ', item)

         node_list[table[i].parentCategoryId].children = {
           ...node_list[table[i].parentCategoryId].children,
           ...item
         };
       }
     }

Expected result:

const table =[
    {  
        "id": 791,
        "sortOrder": 0,
        "parentCategoryId": 833
    },
    {    
        "id": 790,
        "sortOrder": 0,
        "parentCategoryId": 833
    },
    {    
        "id": 845,
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {    
        "id": 844,
        "sortOrder": 0,
        "parentCategoryId": 842
    },
    {    
        "id": 802,
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {    
        "id": 788,
        "sortOrder": 0,
        "parentCategoryId": 833
    },
    {    
        "id": 863,
        "sortOrder": 0,
        "parentCategoryId": 863
    },
    {    
        "id": 858,
        "sortOrder": 0,
        "parentCategoryId": 858
    },
    {    
        "id": 867,
        "sortOrder": 0,
        "parentCategoryId": 867
    },
    {    
        "id": 871,
        "sortOrder": 0,
        "parentCategoryId": 867
    },
    {    
        "id": 801,
        "sortOrder": 0,
        "parentCategoryId": 847
    },    
    {    
        "id": 797,
        "sortOrder": 0,
        "parentCategoryId": 847,
        children:[
            {    
                "id": 792,
                "sortOrder": 0,
                "parentCategoryId": 797,
                children:[
                    {
                        "id": 671,
                        "sortOrder": 0,
                        "parentCategoryId": 792
                    },
                ]
            },
        ]
    },
    {    
        "id": 789,
        "name": "Hot food",
        "sortOrder": 0,
        "parentCategoryId": 833
    },
    {    
        "id": 798,
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {    
        "id": 833,
        "sortOrder": 0,
        "parentCategoryId": 833,
        children:[
            {    
                "id": 785,
                "sortOrder": 0,
                "parentCategoryId": 833
            },
            {
                "id": 786,
                "sortOrder": 0,
                "parentCategoryId": 833
            },
            {
                "id": 787,
                "sortOrder": 0,
                "parentCategoryId": 833
            },
        ]
    },
    {   
        "id": 796,
        "sortOrder": 0,
        "parentCategoryId": 847
    },
    {   
        "id": 843,
        "sortOrder": 0,
        "parentCategoryId": 842
    },
    {   
        "id": 840,
        "sortOrder": 0,
        "parentCategoryId": 793
    },
    {    
        "id": 868,
        "sortOrder": 0,
        "parentCategoryId": 868
    },
    {    
        "id": 851,
        "sortOrder": 0,
        "parentCategoryId": 851
    },
    {    
        "id": 839,
        "sortOrder": 0,
        "parentCategoryId": 847,
        children:[
            {
                "id": 793,
                "sortOrder": 0,
                "parentCategoryId": 839,
                children:[
                    {    
                        "id": 870,
                        "sortOrder": 0,
                        "parentCategoryId": 856
                    },
                ]
            },
        ]
    },
    {    
        "id": 805,
        "sortOrder": 0,
        "parentCategoryId": 859,
        children:[
            {
                "id": 856,
                "sortOrder": 0,
                "parentCategoryId": 805
            },
            {    
                "id": 859,
                "sortOrder": 0,
                "parentCategoryId": 805
            },
        ]
    },      
]
4
  • please add the wanted result as well. Commented Oct 2, 2018 at 12:05
  • added wanted results Commented Oct 2, 2018 at 12:24
  • table and result does not match, for example 792 and 797. Commented Oct 2, 2018 at 12:40
  • I know, as I just din't have time to map manually this .but it shows structure Commented Oct 3, 2018 at 8:21

2 Answers 2

3

Looks like you want to add a children key with an array of values to the objects in your initial array where the id value corresponds to one or more parentCategoryId values from other objects in the array - and no object should be repeated as a parent or child in the array of nested objects.

You could map the array to append children, and then filter to return just the root parents (and orphans). For example (working snippet below the example if you want to see the output):

const ids = table.map((x) => x.id);
const result = table.map((parent) => {
  const children = table.filter((child) => {
    if (child.id !== child.parentCategoryId && child.parentCategoryId === parent.id) {
      return true;
    }

    return false;
  });

  if (children.length) {
    parent.children = children;
  }

  return parent;
}).filter((obj) => {
  if (obj.id === obj.parentCategoryId || !ids.includes(obj.parentCategoryId)) {
    // include ultimate parents and orphans at root
    return true;
  }

  return false;
});

const table = [{ "id": 791, "sortOrder": 0, "parentCategoryId": 833 }, { "id": 790, "sortOrder": 0, "parentCategoryId": 833 }, { "id": 845, "sortOrder": 0, "parentCategoryId": 847 }, { "id": 844, "sortOrder": 0, "parentCategoryId": 842 }, { "id": 802, "sortOrder": 0, "parentCategoryId": 847 }, { "id": 788, "sortOrder": 0, "parentCategoryId": 833 }, { "id": 863, "sortOrder": 0, "parentCategoryId": 863 }, { "id": 858, "sortOrder": 0, "parentCategoryId": 858 }, { "id": 867, "sortOrder": 0, "parentCategoryId": 867 }, { "id": 871, "sortOrder": 0, "parentCategoryId": 867 }, { "id": 801, "name": "Tickets", "sortOrder": 0, "parentCategoryId": 847 }, { "id": 792, "sortOrder": 0, "parentCategoryId": 833 }, { "id": 797, "sortOrder": 0, "parentCategoryId": 847 }, { "id": 789, "name": "Hot food", "sortOrder": 0, "parentCategoryId": 833 }, { "id": 798, "sortOrder": 0, "parentCategoryId": 847 }, { "id": 671, "sortOrder": 0, "parentCategoryId": 847 }, { "id": 833, "sortOrder": 0, "parentCategoryId": 833 }, { "id": 796, "sortOrder": 0, "parentCategoryId": 847 }, { "id": 843, "sortOrder": 0, "parentCategoryId": 842 }, { "id": 840, "sortOrder": 0, "parentCategoryId": 793 }, { "id": 868, "sortOrder": 0, "parentCategoryId": 868 }, { "id": 851, "sortOrder": 0, "parentCategoryId": 851 }, { "id": 839, "sortOrder": 0, "parentCategoryId": 847 }, { "id": 793, "sortOrder": 0, "parentCategoryId": 839 }, { "id": 859, "sortOrder": 0, "parentCategoryId": 859 }, { "id": 805, "sortOrder": 0, "parentCategoryId": 859 }, { "id": 856, "name": "DRINKS", "sortOrder": 0, "parentCategoryId": 805 }, { "id": 870, "sortOrder": 0, "parentCategoryId": 856 }, { "id": 787, "sortOrder": 0, "parentCategoryId": 833 }, { "id": 786, "sortOrder": 0, "parentCategoryId": 833 }, { "id": 799, "sortOrder": 0, "parentCategoryId": 847 }, { "id": 852, "sortOrder": 0, "parentCategoryId": 852 }, { "id": 795, "name": "Gents fragrance", "sortOrder": 0, "parentCategoryId": 847 }, { "id": 864, "sortOrder": 0, "parentCategoryId": 864 }, { "id": 854, "sortOrder": 0, "parentCategoryId": 854 }, { "id": 865, "sortOrder": 0, "parentCategoryId": 865 }, { "id": 869, "name": "GFI", "sortOrder": 0, "parentCategoryId": 869 }, { "id": 785, "sortOrder": 0, "parentCategoryId": 833 }];
const ids = table.map((x) => x.id);
const result = table.map((parent) => {
  const children = table.filter((child) => {
    if (child.id !== child.parentCategoryId && child.parentCategoryId === parent.id) {
      return true;
    }
    
    return false;
  });
  
  if (children.length) {
    parent.children = children;
  }
  
  return parent;
}).filter((obj) => {
  if (obj.id === obj.parentCategoryId || !ids.includes(obj.parentCategoryId)) {
    // include ultimate parents and orphans at root
    return true;
  }
  
  return false;
});

// stringify just to flatten out SO console result for easier result scanning
console.log(JSON.stringify(result));

Sign up to request clarification or add additional context in comments.

3 Comments

thank you @benvc, the only issue I see that the object is still in the root list after getting added as child. so element in the results are repeat.
@ChrisTarasovs I see, in that case the wrapper function needs to be filter instead map - edited the answer to reflect the clarification.
@ChrisTarasovs - changed my mind about starting with the filter, I think mapping first and then filtering is simpler (and more readable) - answer edited accordingly.
3

We have a complex json file that we have to handle with JavaScript to make it hierarchical, in order to later build a tree. Every entry of the JSON array has − id − a unique id, parentId − the id of the parent node (which is 0 if the node is a root of the tree) level − the level of depth in the tree.

The JSON data is already "ordered", means that an entry will have above itself a parent node or brother node, and under itself a child node or a brother node.

    const arr = [
   {
      "id": "12",
      "parentId": "0",
      "text": "Man",
      "level": "1",
      "children": null
   },
   {
      "id": "6",
      "parentId": "12",
      "text": "Boy",
      "level": "2",
      "children": null
   },
   {
      "id": "7",
      "parentId": "12",
      "text": "Other",
      "level": "2",
      "children": null
   },
   {
      "id": "9",
      "parentId": "0",
      "text": "Woman",
      "level": "1",
      "children": null
   },
   {
      "id": "11",
      "parentId": "9",
      "text": "Girl",
      "level": "2",
      "children": null
   }
];
const listToTree = (arr = []) => {
   let map = {}, node, res = [], i;
   for (i = 0; i < arr.length; i += 1) {
      map[arr[i].id] = i;
      arr[i].children = [];
   };
   for (i = 0; i < arr.length; i += 1) {
      node = arr[i];
      if (node.parentId !== "0") {
         arr[map[node.parentId]].children.push(node);
      }
      else {
         res.push(node);
      };
   };
   return res;
};
console.log(JSON.stringify(listToTree(arr), undefined, 4));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.