web-dev-qa-db-de.com

Suchen Sie mit dem Schlüssel tief in einem verschachtelten Objekt

Nehmen wir an, ich habe ein Objekt:

[
    {
        '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':{
                                     ...

Ich möchte das eine Objekt finden, bei dem die ID 1 ist. Gibt es eine Funktion für so etwas? Ich könnte die _.filter-Methode von Underscore verwenden, aber ich müsste oben anfangen und nach unten filtern.

50
Harry

Rekursion ist dein Freund. Ich habe die Funktion aktualisiert, um Property-Arrays zu berücksichtigen:

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;
}

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

63
Zach

Wenn Sie das erste Element abrufen möchten, dessen ID während der Objektsuche 1 ist, können Sie diese Funktion verwenden:

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;
}

Wenn Sie alle Elemente abrufen möchten, deren ID 1 ist, werden alle Elemente, deren ID 1 ist, in result gespeichert.

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);
        }
    }
}
15
haitaka

Ich habe diese Seite durch googeln nach ähnlichen Funktionen gefunden. Basierend auf der Arbeit von Zach und regularmike habe ich eine andere Version erstellt, die meinen Bedürfnissen entspricht.
Übrigens, teriffic work Zah und regularmike! Ich werde den Code hier posten:

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);

}

Was es tut, ist, dass es jedes Objekt innerhalb von obj mit dem Namen und dem Wert der Eigenschaft findet, die mit targetProp und targetValue übereinstimmen, und es in das finalResults-Array schieben wird. Und hier ist das jsfiddle-Spiel: https://jsfiddle.net/alexQch/5u6q2ybc/

4
Alex Quan

Was für mich funktionierte, war dieser faule Ansatz, nicht algorithmisch faul;) 

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

Ich habe eine Bibliothek für diesen Zweck erstellt: https://github.com/dominik791/obj-traverse

Sie können die findFirst()-Methode folgendermaßen verwenden:

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

Jetzt speichert die Variable foundObject eine Referenz auf das Objekt, nach dem Sie suchen.

2
dominik791

Verbesserte Antwort, um Zirkelverweise in Objekten zu berücksichtigen. Es zeigt auch den Weg an, den es genommen hat, um dorthin zu gelangen.

In diesem Beispiel suche ich nach einem iframe, von dem ich weiß, dass er sich irgendwo in einem globalen Objekt befindet:

const objDone = []
var i = 2
function getObject(theObject, k) {
    if (i < 1 || objDone.indexOf(theObject) > -1) return
    objDone.Push(theObject)
    var result = null;
    if(theObject instanceof Array) {
        for(var i = 0; i < theObject.length; i++) {
            result = getObject(theObject[i], i);
            if (result) {
                break;
            }   
        }
    }
    else
    {
        for(var prop in theObject) {
            if(prop == 'iframe' && theObject[prop]) {
                i--;
                console.log('iframe', theObject[prop])
                return theObject[prop]
            }
            if(theObject[prop] instanceof Object || theObject[prop] instanceof Array) {
                result = getObject(theObject[prop], prop);
                if (result) {
                    break;
                }
            } 
        }
    }
    if (result) console.info(k)
    return result;
}

Führen Sie Folgendes aus: getObject(reader, 'reader') gab am Ende die folgende Ausgabe und das iframe-Element aus:

iframe // (The Dom Element)
_views
views
manager
rendition
book
reader

HINWEIS: Der Pfad ist in umgekehrter Reihenfolge reader.book.rendition.manager.views._views.iframe

1
Gerardlamo

Eine andere (etwas alberne) Option besteht darin, die natürlich rekursive Natur von JSON.stringify auszunutzen und ihm eine Ersetzungsfunktion zu übergeben, die auf jedem verschachtelten Objekt während des Stringifizierungsprozesses ausgeführt wird:

const input = [{
  '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': {}
      }]
    }]
  }]
}];

console.log(findNestedObj(input, 'id', '1'));

function findNestedObj(entireObj, keyToFind, valToFind) {
  let foundObj;
  JSON.stringify(input, (_, nestedValue) => {
    if (nestedValue && nestedValue[keyToFind] === valToFind) {
      foundObj = nestedValue;
    }
    return nestedValue;
  });
  return foundObj;
};
0

Verbesserte @haitaka-Antwort mit Schlüssel und Prädikat

function  deepSearch (object, key, predicate) {
    if (object.hasOwnProperty(key) && predicate(key, object[key]) === true) return object

    for (let i = 0; i < Object.keys(object).length; i++) {
      if (typeof object[Object.keys(object)[i]] === "object") {
        let o = deepSearch(object[Object.keys(object)[i]], key, predicate)
        if (o != null) return o
      }
    }
    return null
}

Das kann also aufgerufen werden als:

var result = deepSearch(myObject, 'id', (k, v) => v === 1);

oder

var result = deepSearch(myObject, 'title', (k, v) => v === 'Some Recommends');

Hier ist das jsFiddle: http://jsfiddle.net/ktdx9es7

0
Iulian Pinzaru