陣列過濾只能由aggregation framework完成。它允許對文檔進行更多的操作,而不是基本投影。
就像任何查詢一樣,你應該總是先使用$match
管道,以便在可能的情況下使用索引。不管之後正在執行什麼其他操作:
db.employee.aggregate([
// Always match first to reduce results
{ "$match": {
"employee.email": { "$in": ["[email protected]", "[email protected]"] }
}},
// Unwind to de-normalize the array elements as documents
{ "$unwind": "$employee" },
// Match to "filter" the array content
{ "$match": {
"employee.email": { "$in": ["[email protected]", "[email protected]"] }
}},
// Group back to a document with the array
{ "$group": {
"_id": "$_id",
"employee": { "$push": "$employee" }
}},
// Optionally project to remove the "_id" field from results
{ "$project": {
"_id": 0,
"employee": 1
}}
])
這樣就解釋了基本過程。在找到符合條件的「文檔」之後,您可以使用$unwind
有效地將數組的每個元素獨立爲文檔,共享任何父字段。額外的$match
用於「過濾」結果中的那些元素。當$group
完成時,只有匹配的元素被放回到數組中。
對於MongoDB 2.6,你可以用不同的方式來做到這一點,這應該適用於更大的數組。有一些新的運算符,如$map
用於在不使用$unwind
的情況下處理「內聯」陣列。還有其他「設置」過濾選項,如$setDifference
。所以,你可以做到這一點您的文檔始終包含在各自爲陣獨特的「電子郵件」值:
db.employee.aggregate([
// Always match first to reduce results
{ "$match": {
"employee.email": { "$in": ["[email protected]", "[email protected]"] }
}},
// Project filtered array content "in-line"
{ "$project": {
"_id": 0,
"employee": {
"$setDifference": [
{ "$map": {
"input": "$employee",
"as": "el",
"in": {
"$cond": [
{ "$or": [
{ "$eq": [ "$$el.email", "[email protected]" ] },
{ "$eq": [ "$$el.email", "[email protected]" ] }
]},
"$$el",
false
]
}
}},
[false]
]
}
}}
])
從前面提到的
$cond
操作者用在這裏是數組中的每個元素評估新運營商
除了通過$map
看看是否符合條件。如果是這樣,則元素返回結果數組中,否則元素爲false
。
$setDifference
運算符然後「過濾」返回的「set」中的任何false
值,就像任何重複數據一樣,所以數組元素在每個文檔中需要如前所述是唯一的。
對於「非唯一」的元素,總有這樣的替代品在現代版本的第一方法,以及:
db.employee.aggregate([
// Always match first to reduce results
{ "$match": {
"employee.email": { "$in": ["[email protected]", "[email protected]"] }
}},
// Redact removes document levels that do not match the condition
{ "$redact": {
"$cond": [
{ "$or": [
{ "$eq": [
{ "$ifNull": [ "$email", "[email protected]" ] },
"[email protected]"
]},
{ "$eq": [
{ "$ifNull": [ "$email", "[email protected]" ] },
"[email protected]"
]}
]},
"$$DESCEND",
"$$PRUNE"
]
}}
])
這使用$redact
以略微做作方法,以消除從文檔的數組元素那與條件不符。這裏的問題是$redact
是遞歸的,所以我們測試被測場的存在以及它不存在的地方只是返回一個值來匹配。實際上真的只需要一個$ifNull
聲明。
本質上,無論您選擇什麼方法,它都是aggregation framework,它具有對基本投影可以執行的文檔的「加強」操縱。
謝謝@尼爾,這樣一個輝煌的解釋。 – FRizal 2014-11-04 02:10:02