2014-11-23 99 views
1

我想獲取符合我的條件的子文檔。MongoDB elemMatch不能正常工作

我的MongoDB的查詢這樣的:

db.SCSIssue.find(
{ _id: ObjectId("5439a2992ea8cc0f70feef2d") }, 
{ Statuses: { $elemMatch: { StatusID: { $gte : NumberLong(521055087020736513) } } } } 
) 

我的架構類似的:

{ 
    .... 
    "_id": ObjectId("5439a2992ea8cc0f70feef2d"), 
    .... 
    "Statuses": [{ 
     .... 
     "StatusID": NumberLong(525623822633172993), 
    },{ 
     .... 
     "StatusID": NumberLong(521055087020736513), 
    },{ 
     .... 
     "StatusID": NumberLong(521060802959532033), 
    }] 
    .... 
}, 
{ 
    .... 
    "_id": ObjectId("543c04662ea8cd11ec4dda5f"), 
    .... 
    "Statuses": [{ 
     .... 
     "StatusID": NumberLong(535623822633172993), 
    },{ 
     .... 
     "StatusID": NumberLong(541055087020736513), 
    },{ 
     .... 
     "StatusID": NumberLong(551060802959532033), 
    }] 
    .... 
}, 
.... 

查詢結果:

{ 
    "_id" : ObjectId("5439a2992ea8cc0f70feef2d"), 
    "Statuses" : [{ 
     .... 
     "StatusID": NumberLong(525623822633172993), 
     .... 
    }] 
} 

預期結果:

{ 
    "_id" : ObjectId("5439a2992ea8cc0f70feef2d"), 
    "Statuses" : [{ 
     .... 
     "StatusID": NumberLong(521055087020736513), 
    },{ 
     .... 
     "StatusID": NumberLong(521060802959532033), 
    }] 
} 

簡而言之,我想獲取大於或等於我的條件和相同時間的數組(子狀態)中的子文檔,這些_id等於我的條件。我讀了很多關於這個的答案。他們都喜歡我的問題,但在我的情況下,它沒有預期的工作。

我錯過了什麼? 謝謝。

回答

0

$elemMatch的行爲沒有任何問題。它按預期工作。該文檔還說:

但是,$ elemMatch投影僅返回數組中第一個匹配的 元素。

作爲一個經驗法則,只要你投影array使用$elemMatch只有一個元素將被投影最多。如果數組中沒有任何元素匹配,則該字段根本不會投影。

因此,您得到的結果是正確的,只有匹配$elemMatch中條件的數組中的第一項將是projected

{ 
    "_id" : ObjectId("5439a2992ea8cc0f70feef2d"), 
    "Statuses" : [{ 
     .... 
     "StatusID": NumberLong(525623822633172993), 
     .... 
    }] 
} 

您可以嘗試改變的狀態數組中文檔的順序,如果該文件出現提前陣列中的其它匹配的文件可能會得到不同的匹配文檔。

參見:$elemMatch

來到您的要求,如果你想在所有的結果匹配的數組元素,你需要執行聚集操作。

  • Match具有所要求的_id文件和​​那些包含我們正在搜索的狀態子文檔文件 。
  • unwind狀態數組。
  • 再次match單個展開的文件。
  • 最後group匹配的文件由_id

驗證碼:

db.collection.aggregate([ 
{$match:{ "_id": ObjectId("5439a2992ea8cc0f70feef2d"), 
      "Statuses.StatusID":{$gte : NumberLong(525623822633172993)}}}, 
{$unwind:"$Statuses"}, 
{$match:{"Statuses.StatusID":{$gte : NumberLong(525623822633172993)}}}, 
{$group:{"_id":"$_id",statuses:{$push:"$Statuses"}}} 
]) 

,這將給你陣列中所有匹配的子文件。

+0

謝謝你的回答。我還有一個關於你的查詢的問題。爲什麼你使用「Statuses.StatusID」匹配兩次?有什麼技巧嗎? – Dreamcatcher 2014-11-24 20:44:32

+0

在初始匹配操作階段添加條件將防止以下不必要的展開和匹配操作符,如果文檔沒有具有匹配的statusId的狀態子文檔。 – BatScream 2014-11-24 21:09:35