it-swarm.com.de

So finden Sie Dokumente und einzelne Filialdokumente, die bestimmte Kriterien in der MongoDB-Sammlung abgleichen

Ich habe eine Sammlung von Produkten. Jedes Produkt enthält eine Reihe von Artikeln.

> db.products.find().pretty()
{
    "_id" : ObjectId("54023e8bcef998273f36041d"),
    "shop" : "shop1",
    "name" : "product1",
    "items" : [
            {
                    "date" : "01.02.2100",
                    "purchasePrice" : 1,
                    "sellingPrice" : 10,
                    "count" : 15
            },
            {
                    "date" : "31.08.2014",
                    "purchasePrice" : 10,
                    "sellingPrice" : 1,
                    "count" : 5
            }
    ]
}

Können Sie mir bitte einen Rat geben, wie ich MongoDB abfragen kann, um alle Produkte mit nur einem Artikel abzurufen, dessen Datum dem Datum entspricht, an dem ich als Parameter die Abfrage übergebe.

Das Ergebnis für "31.08.2014" muss sein: 

    {
    "_id" : ObjectId("54023e8bcef998273f36041d"),
    "shop" : "shop1",
    "name" : "product1",
    "items" : [
            {
                    "date" : "31.08.2014",
                    "purchasePrice" : 10,
                    "sellingPrice" : 1,
                    "count" : 5
            }
    ]
}
13
evgeniy44

Was Sie suchen, ist der positionelle $ Operator und "Projektion". Für ein einzelnes Feld müssen Sie das erforderliche Array-Element mit "Punktnotation" abgleichen. Für mehrere Felder verwenden Sie $elemMatch :

db.products.find(
    { "items.date": "31.08.2014" },
    { "shop": 1, "name":1, "items.$": 1 }
)

Oder der $elemMatch für mehr als ein übereinstimmendes Feld:

db.products.find(
    { "items":  { 
        "$elemMatch": { "date": "31.08.2014",  "purchasePrice": 1 }
    }},
    { "shop": 1, "name":1, "items.$": 1 }
)

Diese funktionieren jedoch nur für ein einzelnes Array-Element, und nur ein Element wird zurückgegeben. Wenn Sie möchten, dass mehr als ein Arrayelement aus Ihren Bedingungen zurückgegeben wird, benötigen Sie eine erweiterte Behandlung mit dem Aggregationsframework.

db.products.aggregate([
    { "$match": { "items.date": "31.08.2014" } },
    { "$unwind": "$items" },
    { "$match": { "items.date": "31.08.2014" } },
    { "$group": {
        "_id": "$_id",
        "shop": { "$first": "$shop" },
        "name": { "$first": "$name" },
        "items": { "$Push": "$items" }
    }}
])

Oder möglicherweise in kürzerer/schnellerer Form seit MongoDB 2.6, wo Ihr Array von Elementen eindeutige Einträge enthält:

db.products.aggregate([
    { "$match": { "items.date": "31.08.2014" } },
    { "$project": {
        "shop": 1,
        "name": 1,
        "items": {
            "$setDifference": [
                { "$map": {
                    "input": "$items",
                    "as": "el",
                    "in": {
                        "$cond": [
                            { "$eq": [ "$$el.date", "31.08.2014" ] },
                            "$$el",
                            false 
                        ]
                    }
                }},
                [false]
            ]
        }
    }}
])

Oder möglicherweise mit $redact , aber ein wenig erfunden:

db.products.aggregate([
    { "$match": { "items.date": "31.08.2014" } },
    { "$redact": {
        "$cond": [
             { "$eq": [ { "$ifNull": [ "$date", "31.08.2014" ] }, "31.08.2014" ] },
             "$$DESCEND",
             "$$Prune"
         ]
    }}
])

Es hängt also nur davon ab, ob Sie immer davon ausgehen, dass ein einzelnes Element oder mehrere Elemente übereinstimmen und welcher Ansatz dann besser ist. Wenn möglich, ist die .find()-Methode jedoch in der Regel schneller, da ihnen der Overhead der anderen Operationen fehlt, der in den letzten Formularen nicht weit hinterherhinkt.

Nebenbei bemerkt werden Ihre "Datumsangaben" als Strings dargestellt, was in Zukunft keine sehr gute Idee ist. Erwägen Sie, diese in richtige Date Objekttypen zu ändern, was Ihnen in Zukunft sehr helfen wird.

31
Neil Lunn

Mongo unterstützt Punktnotation für Unterabfragen. 

Siehe: http://docs.mongodb.org/manual/reference/glossary/#term-dot-notation

Abhängig von Ihrem Fahrer möchten Sie Folgendes: 

db.products.find({"items.date":"31.08.2014"});

Beachten Sie, dass das Attribut in Anführungszeichen für Punktnotation steht, auch wenn Ihr Treiber dies normalerweise nicht erfordert.

0