MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

MongoDB elemmatch mehrere Elemente im Array

Sie können nicht mehrere Elemente eines Arrays zurückgeben, die Ihren Kriterien in irgendeiner Form eines einfachen .find() entsprechen Anfrage. Um mehr als ein Element abzugleichen, müssen Sie .aggregate() verwenden Methode statt.

Der Hauptunterschied besteht hier darin, dass die "Abfrage" genau das tut, was sie tun soll, und "Dokumente" findet, die Ihren Bedingungen entsprechen. Sie können versuchen, den Positionscode $ zu verwenden -Operator innerhalb eines Projektionsarguments, aber die dortigen Regeln lauten, dass er nur mit dem "ersten" Array-Element übereinstimmt, das den Abfragebedingungen entspricht.

Um nach mehreren Array-Elementen zu "filtern", gehen Sie wie folgt vor:

db.sample.aggregate([
    // Filter possible documents
    { "$match": { "filtermetric.class": "s2" } },

    // Unwind the array to denormalize
    { "$unwind": "$filtermetric" },

    // Match specific array elements
    { "$match": { "filtermetric.class": "s2" } },

    // Group back to array form
    { "$group": {
        "_id": "$_id",
        "filtermetric": { "$push": "$filtermetric" }
    }}
])

In modernen Versionen von MongoDB ab Version 2.6 können Sie dies mit $redact tun :

db.sample.aggregate([
    // Filter possible documents
    { "$match": { "filtermetric.class": "s2" } },

    // Redact the entries that do not match
    { "$redact": {
        "$cond": [
            { "$eq": [ { "$ifNull": [ "$class", "s2" ] }, "s2" ] },
            "$$DESCEND",
            "$$PRUNE"
        ]
    }}
])

Das ist wahrscheinlich Ihre effizienteste Option, aber es ist rekursiv, also betrachten Sie zuerst Ihre Dokumentstruktur, da das gleichnamige Feld auf keiner Ebene mit einer anderen Bedingung existieren kann.

Möglicherweise sicherer, aber nur nützlich, wenn die Ergebnisse im Array "wirklich eindeutig" sind, ist diese Technik mit $map und $setDifference :

db.sample.aggregate([
    { "$project": {
        "filtermetric": { "$setDifference": [
            { "$map": [
                "input": "$filtermetric",
                "as": "el",
                "in": {"$cond": [
                    { "$eq": [ "$$el.class", "s2" ] },
                    "$$el",
                    false
                ]}
            ]},
            [false]
        ]}
    }}
])

Beachten Sie auch, dass sowohl in der $group und $project operative Pipeline-Phasen, die Sie benötigen um alle Felder anzugeben, die Sie ab diesem Zeitpunkt in Ihren Ergebnisdokumenten zurückgeben möchten.

Der letzte Hinweis ist, dass $elemMatch ist nicht erforderlich, wenn Sie nur den Wert eines einzelnen Schlüssels innerhalb eines Arrays abfragen. Die Punktnotation wird bevorzugt und empfohlen, wenn nur auf einen einzelnen Schlüssel des Arrays zugegriffen wird. $elemMatch sollte nur benötigt werden, wenn "mehrere" Schlüssel im Dokument innerhalb des Arrays "element" einer Abfragebedingung entsprechen müssen.