2014-08-30 59 views
11

我有產品集合。每個產品都包含一系列項目。如何在MongoDB集合中找到與給定標準匹配的文檔和單個子文檔

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

所以,可以請你給我一個建議,我怎麼能MongoDB的查詢檢索與該日期是等於我通過查詢作爲參數的日期只有單個項目的所有產品。

爲 「2014年8月31日」 的結果必然是:

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

從3.2開始使用'$ filter'。更多在這裏https://stackoverflow.com/questions/3985214/retrieve-only-the-queried-element-in-an-object-array-in-mongodb-collection – Veeram 2017-12-13 19:47:49

回答

26

你所尋找的是the positional $運營商和 「投影」。對於單場則需要使用「點號」所要求的數組元素來搭配,爲多個領域使用$elemMatch

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

還是$elemMatch一個以上的匹配字段:

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

這些僅適用於單個數組元素,但只會返回一個數組元素。如果您希望從條件中返回多個數組元素,那麼您需要使用聚合框架進行更高級的處理。

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

或可能在較短/更快的形式,因爲MongoDB的2.6在您的項目數組中包含的唯一條目:

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] 
      ] 
     } 
    }} 
]) 
$redact

還是可能的,但有點做作:

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

所以它只取決於你是否總希望單個元素匹配或多個元素,然後哪種方法更好。但是,如果可能的話,.find()方法通常會更快,因爲它缺少其他操作的開銷,而這些操作在最後一種形式中根本不落後。

作爲一個便箋,你的「日期」被表示爲字符串,這不是一個好主意。考慮將這些改爲適當的Date對象類型,這對你將來會有很大的幫助。

+0

謝謝!很好的答案!這絕對是我正在尋找的,甚至更多。 – evgeniy44 2014-08-31 11:39:59

+0

謝謝。你已經詳細解釋了它 – 2017-12-30 08:38:15

相關問題