Vì yêu cầu của bạn là chỉ "chiếu" tài liệu nên trường bị che, có, khung tổng hợp là một công cụ để thực hiện việc này. Tuy nhiên, bạn phải mất một chút thời gian để tìm hiểu quy trình khi giải nén các mảng và tạo lại.
Vì vậy, những gì bạn muốn là cái này:
db.collection.aggregate([
{ "$unwind": "$questions" },
{ "$unwind": "$questions.answers" },
{ "$group": {
"_id": {
"_id": "$_id",
"name": "$name",
"description": "$description",
"qid": "$questions._id",
"question": "$questions.question"
},
"answers": {
"$push": {
"_id": "$questions.answers._id",
"answer": "$questions.answers.answer"
}
}
}},
{ "$project": {
"questions": {
"_id": "$_id.qid",
"question": "$_id.question",
"answers": "$answers"
}
}},
{ "$sort": { "_id": 1, "questions._id": 1 } },
{ "$group": {
"_id": "$_id._id",
"name": { "$first": "$_id.name" },
"description": { "$first": "$_id.description" },
"questions": { "$push": "$questions" }
}}
])
Nhưng thực sự, nếu bạn có phiên bản MongoDB 2.6 trở lên thì bạn không cần phải $ unwind
và $ group
kết quả trở lại cùng nhau để bỏ qua trường đó. Giờ đây, bạn có thể thực hiện việc này bằng cách sử dụng $ project
và $ map
toán tử hoạt động với mảng:
db.collection.aggregate([
{ "$project": {
"name": 1,
"description": 1,
"questions": {
"$map": {
"input": "$questions",
"as": "q",
"in": {
"$ifNull": [
{
"_id": "$$q._id",
"question": "$$q.question",
"answers": {
"$map": {
"input": "$$q.answers",
"as": "el",
"in": {
"$ifNull": [
{ "_id": "$$el._id", "answer": "$$el.answer" },
false
]
}
}
}
},
false
]
}
}
}
}}
])
Xin lỗi vì phần thụt lề cuộn ra khỏi trang ở đó một chút, nhưng so sánh thì vẫn dễ đọc hơn.
$ map
đầu tiên
xử lý mảng câu hỏi tại chỗ và nguồn cấp dữ liệu cho $ ifNull
trong đó chỉ là vì phần "trong" của $ map
nhà điều hành dự kiến đánh giá một điều kiện trên mỗi phần tử đó.
Nhìn chung, nhanh hơn một chút, vì bạn không phải đi qua $ unwind
và $ group
hoạt động chỉ để loại bỏ trường. Vì vậy, nó thực sự chỉ trở thành "dự báo" mà bạn có thể mong đợi.