Find by key deep in a nested object

2019-01-01 10:50发布

问题:

Let\'s say I have an object:

[
    {
        \'title\': \"some title\"
        \'channel_id\':\'123we\'
        \'options\': [
                    {
                \'channel_id\':\'abc\'
                \'image\':\'http://asdasd.com/all-inclusive-block-img.jpg\'
                \'title\':\'All-Inclusive\'
                \'options\':[
                    {
                        \'channel_id\':\'dsa2\'
                        \'title\':\'Some Recommends\'
                        \'options\':[
                            {
                                \'image\':\'http://www.asdasd.com\'                                 \'title\':\'Sandals\'
                                \'id\':\'1\'
                                \'content\':{
                                     ...

I want to find the one object where the id is 1. Is there a function for something like this? I could use Underscore\'s _.filter method, but I would have to start at the top and filter down.

回答1:

Recursion is your friend. I updated the function to account for property arrays:

function getObject(theObject) {
    var result = null;
    if(theObject instanceof Array) {
        for(var i = 0; i < theObject.length; i++) {
            result = getObject(theObject[i]);
            if (result) {
                break;
            }   
        }
    }
    else
    {
        for(var prop in theObject) {
            console.log(prop + \': \' + theObject[prop]);
            if(prop == \'id\') {
                if(theObject[prop] == 1) {
                    return theObject;
                }
            }
            if(theObject[prop] instanceof Object || theObject[prop] instanceof Array) {
                result = getObject(theObject[prop]);
                if (result) {
                    break;
                }
            } 
        }
    }
    return result;
}

updated jsFiddle: http://jsfiddle.net/FM3qu/7/



回答2:

If you want to get the first element whose id is 1 while object is being searched, you can use this function:

function customFilter(object){
    if(object.hasOwnProperty(\'id\') && object[\"id\"] == 1)
        return object;

    for(var i=0; i<Object.keys(object).length; i++){
        if(typeof object[Object.keys(object)[i]] == \"object\"){
            var o = customFilter(object[Object.keys(object)[i]]);
            if(o != null)
                return o;
        }
    }

    return null;
}

If you want to get all elements whose id is 1, then (all elements whose id is 1 are stored in result as you see):

function customFilter(object, result){
    if(object.hasOwnProperty(\'id\') && object.id == 1)
        result.push(object);

    for(var i=0; i<Object.keys(object).length; i++){
        if(typeof object[Object.keys(object)[i]] == \"object\"){
            customFilter(object[Object.keys(object)[i]], result);
        }
    }
}


回答3:

I found this page through googling for the similar functionalities. Based on the work provided by Zach and regularmike, I created another version which suits my needs.
BTW, teriffic work Zah and regularmike! I\'ll post the code here:

function findObjects(obj, targetProp, targetValue, finalResults) {

  function getObject(theObject) {
    let result = null;
    if (theObject instanceof Array) {
      for (let i = 0; i < theObject.length; i++) {
        getObject(theObject[i]);
      }
    }
    else {
      for (let prop in theObject) {
        if(theObject.hasOwnProperty(prop)){
          console.log(prop + \': \' + theObject[prop]);
          if (prop === targetProp) {
            console.log(\'--found id\');
            if (theObject[prop] === targetValue) {
              console.log(\'----found porop\', prop, \', \', theObject[prop]);
              finalResults.push(theObject);
            }
          }
          if (theObject[prop] instanceof Object || theObject[prop] instanceof Array){
            getObject(theObject[prop]);
          }
        }
      }
    }
  }

  getObject(obj);

}

What it does is it find any object inside of obj with property name and value matching to targetProp and targetValue and will push it to the finalResults array. And Here\'s the jsfiddle to play around: https://jsfiddle.net/alexQch/5u6q2ybc/



回答4:

I\'ve created library for this purpose: https://github.com/dominik791/obj-traverse

You can use findFirst() method like this:

var foundObject = findFirst(rootObject, \'options\', { \'id\': \'1\' });

And now foundObject variable stores a reference to the object that you\'re looking for.



回答5:

What worked for me was this lazy approach, not algorithmically lazy ;)

if( JSON.stringify(object_name).indexOf(\"key_name\") > -1 ) {
    console.log(\"Key Found\");
}
else{
    console.log(\"Key not Found\");
}


回答6:

If you\'re already using Underscore, use _.find()

_.find(yourList, function (item) {
    return item.id === 1;
});