2014-08-30 8 views
11

Ich habe eine Sammlung von Produkten. Jedes Produkt enthält eine Reihe von Elementen.So finden Sie Dokumente und einzelne Filialdokumente, die bestimmten Kriterien in der MongoDB-Sammlung entsprechen

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

So können Sie bitte geben Sie mir einen Rat, wie ich MongoDB abfragen können alle Produkte mit nur einzelne Element abzurufen, das Datum auf das Datum ist gleich I als Parameter abzufragen geben.

Das Ergebnis für "2014.08.31" muss sein:

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

Verwenden Sie '$ filter' ab 3.2. Mehr hier https://stackoverflow.com/questions/3985214/retrieve-only-the-queried-element-in-an-object-array-in-mongodb-collection – Veeram

Antwort

26

Was Sie suchen ist the positional $ Operator und "Projektion". mit „Punktnotation“, für ein einzelnes Feld müssen Sie das gewünschte Array-Element passend für mehr als ein Feld Verwendung $elemMatch:

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

Oder die $elemMatch für mehr als ein Anpassungsfeld:

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

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

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/schnellen Form seit MongoDB 2.6, wo Ihre Array von Elementen eindeutige Einträge enthalten:

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 vielleicht mit $redact, aber ein wenig gekünstelt:

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 erwarten, dass ein einzelnes Element mit mehreren Elementen übereinstimmt und dann, welcher Ansatz besser ist. Aber wo immer es möglich ist, wird die Methode .find() im Allgemeinen schneller sein, da es den Overhead der anderen Operationen nicht aufweist, die in den letzten zu Formen überhaupt nicht so weit zurückbleiben.

Als eine Randnotiz werden Ihre "Daten" als Strings dargestellt, was keine gute Idee ist. Überlegen Sie, ob Sie diese in richtige Date Objekttypen ändern, die Ihnen in Zukunft sehr helfen werden.

+0

Danke! Gute Antwort! Es ist definitiv das, wonach ich suchte und noch mehr. – evgeniy44

+0

Danke. Sie haben es im Detail erklärt –

0

Mongo unterstützt Punktnotation für Unterabfragen.

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

Je nach Fahrer, wollen Sie so etwas wie:

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

Beachten Sie, dass das Attribut in Anführungszeichen für Punktnotation ist, auch wenn in der Regel Ihre Fahrer dies nicht erforderlich ist.

Verwandte Themen