user630209
user630209

Reputation: 1207

Loop through nested JSON child objects

I have this JSON payload, where each object contains an ID, name and array of children. Here I need to get the IDs of all the elements, including the root and all the nested children.

{
  "_id": "-1",
  "_name": "root",
  "_children": [
    {
      "_id": "1",
      "_name": "Child 1",
      "_children": [
        {
          "_id": "1-1",
          "_name": "Child 1-1",
          "_children": [
            {
              "_id": "1-1-1",
              "_name": "Child 1-1-1",
              "_children": [

              ]
            }
          ]
        },
        {
          "_id": "1-2",
          "_name": "Child 1-2",
          "_children": [

          ]
        },
        {
          "_id": "1-3",
          "_name": "Child 1-3",
          "_children": [

          ]
        }
      ]
    },
    {
      "_id": "2",
      "_name": "Child 2",
      "_children": [
        {
          "_id": "2-2",
          "_name": "Child 2-2",
          "_children": [

          ]
        }
      ]
    }
  ]
}

How can I loop through this to get the ID values of all children and the root?

This is what I had tried using a nested function, but it is not working.

getNestedChildren(arr) {
  var out = []
    for(var i in arr[0].children) {
      out.push(arr[i].id);
        if(arr[i].children && arr[i].children.size() > 0) {
            var children = this.getNestedChildren(arr[i].children)
        }
    }

Upvotes: 2

Views: 2853

Answers (3)

kaya3
kaya3

Reputation: 51037

Here's a solution which works essentially the same way as @samdouble's answer; push the current node's ID to a result array, then recurse on the node's children.

The result array has to be created before calling the recursive function, so for convenience, that can be wrapped in an outer function; this saves the caller having to create an empty array to pass to the function.

interface TreeNode {
    _id: string;
    _name: string;
    _children: TreeNode[];
}

function getIds(data: TreeNode): string[] {
    const result: string[] = [];
    function helper(node: TreeNode): void {
        result.push(node._id);
        node._children.forEach(helper);
    }
    helper(data);
    return result;
}

Playground Link

Upvotes: 1

samdouble
samdouble

Reputation: 474

You can use recursion and modify a "result array" by reference.

For example, if your nested object is stored in a variable data, then:

function addNestedChildrenToArray(obj, resultArray) {
    resultArray.push(obj._id);
    obj._children.forEach(child => addNestedChildrenToArray(child, resultArray));
}

const resultArray = [];
addNestedChildrenToArray(data, resultArray);
// resultArray now contains the results
console.log(resultArray);

You can test it here: https://es6console.com/k6ehwu5p/

Upvotes: 4

mykhailo.romaniuk
mykhailo.romaniuk

Reputation: 1088

You can flatten a tree and then simply get ids. See working example here

const tree = {
  "_id": "-1",
  "_name": "root",
  "_children": [
    // ...
  ]
}

function flattenTree(tree) {
  if (!tree) {
      return [];
  }

  if (tree._children) {
      const result = tree._children.reduce((prev, current) => prev.concat(flattenTree(current)), [tree]);
      return result;
  } else {
      return [tree];
  }
}

const plain = flattenTree(tree);
const ids = plain.map(value => value._id);

Upvotes: 1

Related Questions