Cập nhật năm 2017
Một câu hỏi hay như vậy xứng đáng có một câu trả lời hiện đại. Loại lọc mảng được yêu cầu thực sự có thể được thực hiện trong các bản phát hành MongoDB hiện đại, post 3.2 chỉ qua $match
và $project
các giai đoạn đường ống, giống như hoạt động truy vấn đơn giản ban đầu dự định.
db.accounts.aggregate([
{ "$match": {
"email" : "[email protected]",
"groups": {
"$elemMatch": {
"name": "group1",
"contacts.localId": { "$in": [ "c1","c3", null ] }
}
}
}},
{ "$addFields": {
"groups": {
"$filter": {
"input": {
"$map": {
"input": "$groups",
"as": "g",
"in": {
"name": "$$g.name",
"contacts": {
"$filter": {
"input": "$$g.contacts",
"as": "c",
"cond": {
"$or": [
{ "$eq": [ "$$c.localId", "c1" ] },
{ "$eq": [ "$$c.localId", "c3" ] }
]
}
}
}
}
}
},
"as": "g",
"cond": {
"$and": [
{ "$eq": [ "$$g.name", "group1" ] },
{ "$gt": [ { "$size": "$$g.contacts" }, 0 ] }
]
}
}
}
}}
])
Điều này sử dụng $filter
và $map
toán tử để chỉ trả về các phần tử từ mảng đáp ứng các điều kiện và hiệu suất tốt hơn nhiều so với việc sử dụng $unwind
. Vì các giai đoạn đường ống phản ánh hiệu quả cấu trúc của "truy vấn" và "dự án" từ .find()
hoạt động, hiệu suất ở đây về cơ bản ngang bằng với như vậy và hoạt động.
Lưu ý rằng mục đích thực sự hoạt động ở đâu "trên toàn bộ tài liệu" để tập hợp các chi tiết lại với nhau từ "nhiều" tài liệu thay vì "một", thì điều này thường sẽ yêu cầu một số loại $unwind
để làm như vậy, chẳng hạn như cho phép các mục mảng có thể truy cập được để "phân nhóm".
Về cơ bản đây là cách tiếp cận:
db.accounts.aggregate([
// Match the documents by query
{ "$match": {
"email" : "[email protected]",
"groups.name": "group1",
"groups.contacts.localId": { "$in": [ "c1","c3", null ] },
}},
// De-normalize nested array
{ "$unwind": "$groups" },
{ "$unwind": "$groups.contacts" },
// Filter the actual array elements as desired
{ "$match": {
"groups.name": "group1",
"groups.contacts.localId": { "$in": [ "c1","c3", null ] },
}},
// Group the intermediate result.
{ "$group": {
"_id": { "email": "$email", "name": "$groups.name" },
"contacts": { "$push": "$groups.contacts" }
}},
// Group the final result
{ "$group": {
"_id": "$_id.email",
"groups": { "$push": {
"name": "$_id.name",
"contacts": "$contacts"
}}
}}
])
Đây là "lọc mảng" trên nhiều kết quả phù hợp mà các khả năng chiếu cơ bản của .find()
không làm được.
Bạn có các mảng "lồng vào nhau", do đó bạn cần xử lý $unwind
hai lần. Cùng với các hoạt động khác.