Skip to content Skip to sidebar Skip to footer

Search Nested Object And Return Whole Path

I have below JavaScript with n level children and want to search for id and if any of item from has matching id than need to return object from root to matching item. I want to ret

Solution 1:

You could use this function:

functionfindChild(obj, condition) {
    if (Object.entries(condition).every( ([k,v]) => obj[k] === v )) {
        return obj;
    }
    for (const child of obj.children || []) {
        const found = findChild(child, condition);
        // If found, then add this node to the ancestors of the resultif (found) returnObject.assign({}, obj, { children: [found] });
    }
}
// Sample datavar input = { "children": [{ "name": "Home", "title": "Home", "id": "home1", "children": [] }, { "name": "BUSINESS AND ROLE SPECIFIC", "title": "BUSINESS AND ROLE SPECIFIC", "id": "BAR1", "children": [{ "name": "Global Businesses", "title": "Global Businesses", "id": "GB1", "children": [{ "name": "Commercial Banking", "title": "Commercial Banking", "id": "CB1", "children": [{ "name": "FLAGSHIP PROGRAMMES", "title": "FLAGSHIP PROGRAMMES", "id": "FG1", "children": [] }] }] }] }, { "name": "RISK MANAGEMENT", "title": "RISK MANAGEMENT", "id": "RM1", "children": [] } ]},
    search = { id: 'FG1' };

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

You can use this also for searching with multiple conditions, which must be true at the same time:

search = { "name": "Global Businesses", "title": "Global Businesses" };

... would give you the object that has the specified name and title.

Follow-up question

You asked in comments:

Is there way to supply number to not remove children for given node in input. like,

const donotRemoveChildNode = 2; 
console.log(findChild(input, search, donotRemoveChildNode )); 

...so it will not remove that specific node's children if it matches condition?

Here, if we search for { id: 'FG1'} and supply donotRemoveChildNode = 2, it would not remove the first level children for "Commercial banking".

I would say the donotRemoveChildNode would have to be 3, as there are three levels of children arrays in the ancestor-hierarchy of the "Commercial banking" node. A value of 0 would show the first level children of the top-most children property.

Here is how that extra argument would work -- I added some records to the data to illustrate the difference in the output:

functionfindChild(obj, condition, removeChildNodesBefore = Infinity) {
    if (Object.entries(condition).every( ([k,v]) => obj[k] === v )) {
        return obj;
    }
    for (const child of obj.children || []) {
        let found = findChild(child, condition, removeChildNodesBefore - 1);
        if (found) {
            returnObject.assign({}, obj, { 
                children: removeChildNodesBefore <= 0 
                    ? obj.children.map( sibling => 
                        sibling == child ? found 
                                         : Object.assign({}, sibling, {children: []}) 
                      )
                    : [found]
            });
        }
    }
}

var input = { "children": [{ "name": "Home", "title": "Home", "id": "home1", "children": [] }, { "name": "BUSINESS AND ROLE SPECIFIC", "title": "BUSINESS AND ROLE SPECIFIC", "id": "BAR1", "children": [{ "name": "Global Businesses", "title": "Global Businesses", "id": "GB1", "children": [{ "name": "test", "title": "test", "id": "xxx", "children": [{ "name": "testDeep", "title": "test", "id": "deep", "children": []}]}, { "name": "Commercial Banking", "title": "Commercial Banking", "id": "CB1", "children": [{ "name": "test", "title": "test", "id": "yyy", "children": []}, { "name": "FLAGSHIP PROGRAMMES", "title": "FLAGSHIP PROGRAMMES", "id": "FG1", "children": [] }] }] }] }, { "name": "RISK MANAGEMENT", "title": "RISK MANAGEMENT", "id": "RM1", "children": [] } ]},
    search = { id: 'FG1' }

console.log(findChild(input, search, 3));
.as-console-wrapper { max-height: 100%!important; top: 0; }

Solution 2:

functiongetBranch(branches, leaf_id)
{   
    var result_branch = null;

    branches.some(function(branch, idx) {
        if (branch.id == leaf_id) {
            result_branch = Object.assign({}, branch);
            result_branch.children.forEach(function(child, idx) {
                delete result_branch.children[idx].children;
            });

            returntrue;
        } else {
            let target_branch = getBranch(branch.children, leaf_id);

            if (target_branch) {
                result_branch = Object.assign({}, branch);
                delete result_branch.children
                result_branch.children = [target_branch];

                returntrue;    
            }
        }

        returnfalse;
    });

    return result_branch;
}

console.log(getBranch(input.children, 'GB1'));

Solution 3:

One way is to first loop the root children, and then create another function to see if the Id exists in any of it's children.

var data = {
  "children": [{
      "name": "Home",
      "title": "Home",
      "id": "home1",
      "children": []
    },
    {
      "name": "BUSINESS AND ROLE SPECIFIC",
      "title": "BUSINESS AND ROLE SPECIFIC",
      "id": "BAR1",
      "children": [{
        "name": "Global Businesses",
        "title": "Global Businesses",
        "id": "GB1",
        "children": [{
          "name": "Commercial Banking",
          "title": "Commercial Banking",
          "id": "CB1",
          "children": [{
            "name": "FLAGSHIP PROGRAMMES",
            "title": "FLAGSHIP PROGRAMMES",
            "id": "FG1",
            "children": []
          }]
        }]
      }]
    },
    {
      "name": "RISK MANAGEMENT",
      "title": "RISK MANAGEMENT",
      "id": "RM1",
      "children": []
    }
  ]
};

functionhasId( id, data ) {
  if (data.id === id) returntrue;
  if (data.children) {
    for (const child of data.children) {
      if (hasId( id, child)) returntrue;
    }
  }
  returnfalse;
}

functionsearch( id, data ) {
  for (const child of data.children) {
    if (hasId(id, child)) return child;
  }
  returnnull;
}

console.log(search( "FG1", data ));

Post a Comment for "Search Nested Object And Return Whole Path"