Verwenden Sie jQuerys find () für das JSON-Objekt

73

Ähnlich wie bei brnwdrng suche ich nach einer Möglichkeit, ein JSON-ähnliches Objekt zu durchsuchen.
Angenommen, die Struktur meines Objekts ist wie folgt:

TestObj = {
    "Categories": [{
        "Products": [{
            "id": "a01",
            "name": "Pine",
            "description": "Short description of pine."
        },
        {
            "id": "a02",
            "name": "Birch",
            "description": "Short description of birch."
        },
        {
            "id": "a03",
            "name": "Poplar",
            "description": "Short description of poplar."
        }],
        "id": "A",
        "title": "Cheap",
        "description": "Short description of category A."
    },
    {
        "Product": [{
            "id": "b01",
            "name": "Maple",
            "description": "Short description of maple."
        },
        {
            "id": "b02",
            "name": "Oak",
            "description": "Short description of oak."
        },
        {
            "id": "b03",
            "name": "Bamboo",
            "description": "Short description of bamboo."
        }],
        "id": "B",
        "title": "Moderate",
        "description": "Short description of category B."
    }]
};

Ich möchte ein Objekt mit id = "A" erhalten.

Ich habe alle möglichen Dinge ausprobiert wie:

$(TestObj.find(":id='A'"))

aber nichts scheint zu funktionieren.

Kann sich jemand eine Möglichkeit vorstellen, einen Artikel anhand einiger Kriterien abzurufen, ohne "jeder" zu verwenden?

J. Ed
quelle
2
1. Sie haben ein normales JavaScript-Objekt, kein JSON-ähnliches Objekt. Sie verwenden nur die Objektliteralnotation, um sie zu definieren, und JSON ist nur eine Teilmenge davon (aber JSON arbeitet in einem völlig anderen Kontext). benalman.com/news/2010/03/theres-no-such-thing-as-a-json 2. jQuery arbeitet im DOM nicht an beliebigen Objekten. Sie verwenden das falsche Werkzeug für den Job. Es gibt keine andere Möglichkeit, als die Produktarrays zu durchlaufen.
Felix Kling

Antworten:

119

jQuery funktioniert nicht mit einfachen Objektliteralen. Sie können die folgende Funktion auf ähnliche Weise verwenden, um alle IDs (oder andere Eigenschaften) zu durchsuchen, unabhängig von ihrer Tiefe im Objekt:

function getObjects(obj, key, val) {
    var objects = [];
    for (var i in obj) {
        if (!obj.hasOwnProperty(i)) continue;
        if (typeof obj[i] == 'object') {
            objects = objects.concat(getObjects(obj[i], key, val));
        } else if (i == key && obj[key] == val) {
            objects.push(obj);
        }
    }
    return objects;
}

Verwenden Sie wie folgt:

getObjects(TestObj, 'id', 'A'); // Returns an array of matching objects
David Tang
quelle
2
Es ist kein JSON-Objekt. Und dies würde auch bedeuten, dass Sie Arrays for...in
Felix Kling
@Felix, ja, Sie würden Arrays mit durchlaufen, for...inaber wenn ein beliebiges Objekt angegeben wird, gibt es keine Garantie dafür, dass Arrays darin "echte" Arrays sind. Selbst wenn Sie den Konstruktor, bestimmte Methoden wie Slice usw. überprüfen, kann es dennoch expando-Eigenschaften geben, sodass ich keinen Sinn darin sehe, die Logik weiter zu definieren.
David Tang
@ Box9: Ja, die Mühe lohnt sich vielleicht nicht. Nur zu sagen, dass dies zu unerwarteten Ergebnissen führen könnte . Aber das Erkennen von Arrays sollte in Ordnung sein, über Object.prototype.toString.call(obj)die es geben würde [object Array].
Felix Kling
1
@ Felix, ich denke, es hängt davon ab, was Sie als erwartetes Ergebnis für Arrays wollen. Selbst wenn ein Array normal erstellt wird ( []), können Sie ihnen dennoch (nicht numerische) Eigenschaften hinzufügen, über die Sie möglicherweise iterieren möchten oder nicht. Ansonsten hasOwnProperty()schützt die Überprüfung vor dem Iterieren von Eigenschaften des Prototyps.
David Tang
1
@ Box9: Richtig. Scheint, als hätte ich mich zu sehr auf die for...inund Arrays konzentriert, von denen ich nicht wirklich wusste, was du machst hasOwnProperty()... egal, ich nehme alles zurück;) und +1 als Erlösung: o)
Felix Kling
50

Die reine Javascript-Lösung ist besser, aber eine jQuery-Methode wäre die Verwendung der jQuery-Grep- und / oder Map- Methoden. Wahrscheinlich nicht viel besser als $ .each

jQuery.grep(TestObj, function(obj) {
    return obj.id === "A";
});

oder

jQuery.map(TestObj, function(obj) {
    if(obj.id === "A")
         return obj; // or return obj.name, whatever.
});

Gibt ein Array der übereinstimmenden Objekte oder der nachgeschlagenen Werte im Fall einer Karte zurück. Könnte in der Lage sein, das zu tun, was Sie wollen, indem Sie diese einfach verwenden.

In diesem Beispiel müssten Sie jedoch eine Rekursion durchführen, da die Daten kein flaches Array sind und wir beliebige Strukturen, Schlüssel und Werte akzeptieren, genau wie bei den reinen Javascript-Lösungen.

function getObjects(obj, key, val) {
    var retv = [];

    if(jQuery.isPlainObject(obj))
    {
        if(obj[key] === val) // may want to add obj.hasOwnProperty(key) here.
            retv.push(obj);

        var objects = jQuery.grep(obj, function(elem) {
            return (jQuery.isArray(elem) || jQuery.isPlainObject(elem));
        });

        retv.concat(jQuery.map(objects, function(elem){
            return getObjects(elem, key, val);
        }));
    }

    return retv;
}

Im Wesentlichen dieselbe wie die Antwort von Box9, jedoch mit den Funktionen des Dienstprogramms jQuery, wo dies nützlich ist.

········

davenpcj
quelle
2
Ich habe diesen benutzt jQuery.grep(TestObj, function(obj) { return obj.id === "A"; })[0].PropertyName;
Luis Robles
3
Denken Sie bei der Verwendung $.grep()daran, dass ein Array zurückgegeben wird. Das heißt, wenn Sie nach einem einzelnen Artikel suchen, müssen Sie ihn verwenden, um darauf zugreifen zu können$.grep(/* whatever */)[0]
Jason
1
$ .grep () hat mir gerade verdammt große Kopfschmerzen erspart. Mein Problem / meine Lösung hatte nichts mit dem OP zu tun, aber dadurch kann ich eine Datenbank nur einmal abfragen, im Gegensatz zu n- mal. BRAVO!
Erbaker
@davepncj Wenn ich die Zeichenfolge vergleiche, dann hat die Zeichenfolge einen Unterschied, dass ein Buchstabe im Objekt klein und ein Buchstabe im Vergleich der Zeichenfolge groß geschrieben ist. Wie können wir dann diesen Unterschied erkennen (Klein- und Großbuchstabe)
Bhavin Thummar
5

Dies funktioniert bei mir unter [{"id": "data"}, {"id": "data"}]

function getObjects(obj, key, val) 
{
    var newObj = false; 
    $.each(obj, function()
    {
        var testObject = this; 
        $.each(testObject, function(k,v)
        {
            //alert(k);
            if(val == v && k == key)
            {
                newObj = testObject;
            }
        });
    });

    return newObj;
}
byedissident
quelle
3

Für eine Dimension json können Sie Folgendes verwenden:

function exist (json, modulid) {
    var ret = 0;
    $(json).each(function(index, data){
        if(data.modulId == modulid)
            ret++;
    })
    return ret > 0;
}
Raugaral
quelle
2

Sie können JSONPath verwenden

So etwas machen:

results = JSONPath(null, TestObj, "$..[?(@.id=='A')]")

Beachten Sie, dass JSONPath ein Array von Ergebnissen zurückgibt

(Ich habe den Ausdruck "$ .. [? (@. Id == 'A')]" übrigens nicht getestet. Vielleicht muss er mit Hilfe einer Browserkonsole verfeinert werden.)

matt
quelle
-4

Eine weitere Option, die ich erwähnen wollte, ist, dass Sie Ihre Daten in XML konvertieren und dann so verwenden können, jQuery.find(":id='A'")wie Sie es möchten.

Zu diesem Zweck gibt es jQuery-Plugins wie json2xml .

Wahrscheinlich ist der Konvertierungsaufwand nicht wert, aber das sind einmalige Kosten für statische Daten, daher kann dies nützlich sein.

davenpcj
quelle