Skip to content
Advertisement

How to loop through complex JSON tree data?

Problem: I am given JSON tree data that looks something like below:

let TREE_DATA = {
  items: [
    {
      id: '1',
      name: 'alpha',
    },
    {
      id: '2',
      name: 'bravo',
      children: [
        {
          id: '3',
          name: 'charlie',
        },
        {
          id: '4',
          name: 'delta',
        },
        {
          id: '5',
          name: 'emmet',
          children: [
            {
              id: '6',
              name: 'franklin',
            },
            {
              id: '7',
              name: 'glove',
              children: [
                {
                  id: '8',
                  name: 'eight',
                },
                {
                  id: '9',
                  name: 'nine',
                },
              ],
            },
            {
              id: '10',
            },
          ],
        },
        {
          id: '11',
        },
        {
          id: '12',
        },
      ],
    },
    {
      id: '13',
    },
    {
      id: '14',
    },
  ],
};

The objective is to take the json object and its id and find matching object with id. let’s just assume its been parsed so it’s treated like an object.

Basically, I don’t know how deeply each set of id and name is nested.

So I know I would probably come up with some kind of recursion to keep digging with its base until there’s no children.

Normally, I would approach this problem with .Map or .Reduce method to iterate through if it was an array.

function seek(arr, id) {
   return arr.reduce((a, c) => {
    if (a) return a;
    if (c.id === id) return c;
    if (c.children) return test7(c.children, id);
    if (!(c.id === id)) return a; 
  }, null)
}

Since data structure with JSON is a bit different, I’ve given following try

function seek(json, id) {
  for (let key in json) {
    for (let el of key) {
      if (el.id === id) {
        return el;
      } else {
        if (el.children) {
          result = test7(el.children, id);
        }
      }
    }
  }
}

What I am trying to accomplish here is;

seek(TREE_DATA.items, ‘6’) // { “id”: “6”, “name”: “franklin” }

Since this is not an array but an object of complex data sets, I’d probably look into the key value of an object first. Then I’d once again start looping the array in each key and see which one matches. If an object in the array has “key”, children, then I would start the process from the beginning.

I have debugged this through chrome, and I found the loop hole in my approach. When children is found in a data set, then it would start the whole process from the beginning. Since I am looping through the object first, it will face an array rather than the keys in object.

Another attempt I made was to get extract the array out of object items; But the issue is I can’t really think of the way, and also it is not a good permanent solution.

Here are my questions:

  1. What’s a good approach for a problem like this?
  2. What am I missing to achieve the result I want?
  3. What would be a more efficient solution to this?

Note: I am a beginner, and I am trying to learn the material rather than looking for “just an answer”. I would really appreciate if you could provide some explanation. Thanks in advance.

Advertisement

Answer

Handle the items way the same way you handle the children array – use a recursive function that returns one of the top-level objects if the ID matches, or calls itself recursively if a children property is found:

let TREE_DATA={items:[{id:"1",name:"alpha"},{id:"2",name:"bravo",children:[{id:"3",name:"charlie"},{id:"4",name:"delta"},{id:"5",name:"emmet",children:[{id:"6",name:"franklin"},{id:"7",name:"glove",children:[{id:"8",name:"eight"},{id:"9",name:"nine"}]},{id:"10"}]},{id:"11"},{id:"12"}]},{id:"13"},{id:"14"}]};

const findObj = (arr, idToFind) => {
  for (const item of arr) {
    if (item.id === idToFind) return item;
    if (item.children) {
      const recursiveResult = findObj(item.children, idToFind);
      if (recursiveResult) return recursiveResult;
    }
  }
};
console.log(findObj(TREE_DATA.items, '14'));
console.log(findObj(TREE_DATA.items, '11'));

I think using a for loop like I did above is a better approach than reduce, because a for loop can terminate immediately if a match is found (rather than having to iterate through other items first).

Because the key you’re interested in (id) and the recursive structure property name (children) are the same throughout the data structure, there’s no need to loop through key names – just loop through the array.

Advertisement