Có một mẹo cụ thể về cách xử lý vấn đề này, nhưng trước hết nếu bạn có sẵn MongoDB 2.6 trở lên thì bạn thực sự có thể làm những gì bạn muốn mà không cần sử dụng $unwind
. Điều này có thể rất hữu ích cho hiệu suất nếu bạn đang xử lý nhiều tài liệu.
Các toán tử chính ở đây là $map
xử lý mảng tại chỗ và $allElementsTrue
toán tử sẽ đánh giá các trường "kết quả" của bạn. Việc sử dụng "bản đồ" ở đây cho phép cả việc kiểm tra mảng "tests" bên trong để xem nơi nào các trường "kết quả" trong đó đều đáp ứng điều kiện đúng. Trong trường hợp mảng bên ngoài, "kết quả" này có thể được đặt vào các tài liệu đó khi bạn yêu cầu và tất nhiên việc đánh giá đầy đủ cho tài liệu cũng tuân theo các quy tắc tương tự:
db.test.aggregate([
{ "$project": {
"name": 1,
"result": {
"$allElementsTrue": {
"$map": {
"input": "$acts",
"as": "act",
"in": {
"$allElementsTrue": {
"$map": {
"input": "$$act.tests",
"as": "test",
"in": "$$test.result"
}
}
}
}
}
},
"acts": {
"$map": {
"input": "$acts",
"as": "act",
"in": {
"name": "$$act.name",
"result": {
"$allElementsTrue": {
"$map": {
"input": "$$act.tests",
"as": "test",
"in": "$$test.result"
}
}
},
"tests": "$$act.tests"
}
}
}
}}
])
Cách thực hiện việc này trong các phiên bản trước yêu cầu bạn $group
quay lại hai bước để "xây dựng lại" các mảng trong khi thực hiện lại các bài kiểm tra trên các trường "kết quả" đó. Sự khác biệt khác ở đây cũng là sử dụng $min
toán tử dưới dạng false
sẽ được coi là giá trị nhỏ hơn true
và đánh giá theo cùng một khái niệm "allElements":
db.test.aggregate([
{ "$unwind": "$acts" },
{ "$unwind": "$acts.tests" },
{ "$group": {
"_id": {
"_id": "$_id",
"name": "$name",
"actName": "$acts.name"
},
"result": { "$min": "$acts.tests.result" },
"tests": {
"$push": {
"name": "$acts.tests.name",
"result": "$acts.tests.result"
}
}
}},
{ "$group": {
"_id": "$_id._id",
"name": { "$first": "$_id.name" },
"result": { "$min": "$result" },
"acts": {
"$push": {
"name": "$_id.actName",
"result": "$result",
"tests": "$tests"
}
}
}}
])