sql >> Databasteknik >  >> NoSQL >> MongoDB

MongoDB elemmatchar flera element i array

Du kan inte returnera flera element i en array som matchar dina kriterier i någon form av en grundläggande .find() fråga. För att matcha mer än ett element måste du använda .aggregate() metod istället.

Den största skillnaden här är att "frågan" gör precis vad den är tänkt att göra och matchar "dokument" som uppfyller dina villkor. Du kan försöka använda den positionella $ operatorn inom ett projektionsargument, men reglerna där är att den bara matchar det "första" arrayelementet som matchar frågevillkoren.

För att "filtrera" för flera arrayelement, fortsätt enligt följande:

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" }
    }}
])

I moderna versioner av MongoDB som är version 2.6 eller senare kan du göra detta med $redact :

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"
        ]
    }}
])

Det är förmodligen det mest effektiva alternativet, men det är rekursivt så överväg din dokumentstruktur först eftersom samma namngivna fält inte kan existera med något annat villkor på någon nivå.

Möjligen säkrare men bara användbar där resultaten i arrayen är "verkligen unika" är denna teknik med $map och $setDifference :

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

Notera också att i både $group och $project operativa pipeline steg du behöver för att ange alla fält som du tänker returnera i dina resultatdokument från det stadiet.

Den sista anmärkningen är att $elemMatch krävs inte när du bara frågar efter värdet på en enskild nyckel inom en array. "Punktnotation" är att föredra och rekommenderas när du bara använder en enda nyckel i arrayen. $elemMatch bör endast behövas när "flera" nycklar i dokumentet inom arrayen "element" behöver matcha ett frågevillkor.




  1. Vad är det korrekta sättet att hantera Redis-anslutning i Tornado? (Async - Pub/Sub)

  2. Användning av ServiceStack.Redis.Sentinel

  3. MongoDB $allElementsTrue

  4. Ändra åtkomst från MS Excel?