好吧,我已经尝试解决这个问题一段时间了,但似乎在原地踏步。
我的主要目标是深入第二个嵌套数组并完全删除“isCorrectAnswer”属性...该对象基本上是一个项目,它有 2 个问题,每个问题都有 3 个答案选项...
在应用程序的“回答”时间范围内,我需要删除“isCorrectAnswer”,这样用户就无法通过查看正在传递的数据来作弊...然后一旦“回答”时间范围过去,这将是作为完整对象返回,以向用户指示哪些答案是正确的。
从 MongoDB 返回问题和答案的“项目”对象的示例是:
{
"_id" : ObjectId("5397e4b75c4c9bf0509709ab"),
"name" : "Item Name",
"description" : "Item Description",
"questions" : [
{
"_id" : ObjectId("5397eb925d2664177b0fc5a5"),
"question" : "Item Question 1",
"answers" : [
{
"_id" : ObjectId("5397eb925d2664177b0fc5a6"),
"answer" : "Item Question 1 - Answer 1",
"isCorrectAnswer" : true
},
{
"_id" : ObjectId("5397eb925d2664177b0fc5a7"),
"answer" : "Item Question 1 - Answer 2",
"isCorrectAnswer" : false
},
{
"_id" : ObjectId("5397eb925d2664177b0fc5a8"),
"answer" : "Item Question 1 - Answer 3",
"isCorrectAnswer" : false
}
]
},
{
"_id" : ObjectId("5397eb925d2664177b0fc5a9"),
"question" : "Item Question 2",
"answers" : [
{
"_id" : ObjectId("5397eb925d2664177b0fc5aa"),
"answer" : "Item Question 2 - Answer 1",
"isCorrectAnswer" : false
},
{
"_id" : ObjectId("5397eb925d2664177b0fc5ab")
"answer" : "Item Question 2 - Answer 2",
"isCorrectAnswer" : true
},
{
"_id" : ObjectId("5397eb925d2664177b0fc5ac"),
"answer" : "Item Question 3 - Answer 3",
"isCorrectAnswer" : false
}
]
}
]
}
现在,基于我从 MongoDB 类(class)中学到的知识...
我的第一个目标是进行双重展开,将所有内容展平为单个对象结构。
因此,聚合管道中的第一个步骤是:
{ "$unwind": "$questions" },
{ "$unwind": "$questions.answers" }
这很好用...
我的下一步是运行 $project 以删除“isCorrectAnswer”属性:
{ "$project": {
"_id":1,
"name":1,
"description":1,
"questions":{
"_id":"$questions._id",
"question":"$questions.question",
"answers":{
"_id":"$questions.answers._id",
"answer":"$questions.answers.answer"
}
}
}}
这也很好用...
现在我不足的地方是将对象重新组合到原始结构中(没有“isCorrectAnswer”属性)...
我可以在管道中接下来运行这个 $group 命令,它确实有效,但答案不会与他们的问题一起分组
{ "$group":{
"_id":{
"_id":"$_id",
"ordinal":"$ordinal",
"name":"$name",
"description":"$description",
"benefits":"$benefits",
"specialOffer":"$specialOffer",
"choicePoints":"$choicePoints",
"bonusPoints":"$bonusPoints",
"redemptionPoints":"$redemptionPoints",
"questions":"$questions"
}
}}
我仍在掌握聚合框架,更多的是与 $group 命令有关...我想知道是否有任何步骤我应该采取不同的方式或如何运行第二个 $group 以将“答案”组合在一起.
我还假设我需要运行一个最终的 $project 来清理通过 $group 添加的“_id”属性
感谢您的帮助。
德里克
最佳答案
由于您的要求只是“投影”文档,因此字段被屏蔽,是的,聚合框架是执行此操作的工具。不过,在展开数组和重建数组时,您需要花点时间了解这个过程。
所以你想要的是:
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" }
}}
])
但实际上,如果您有 MongoDB 2.6 或更高版本,则不需要 $unwind
和 $group
结果一起返回以省略该字段。您现在可以使用 $project
执行此操作和 $map
与数组一起使用的运算符:
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
]
}
}
}
}}
])
抱歉缩进稍微超出了页面,但相比之下还是更容易阅读。
第一个$map
就地处理问题数组并提供给内部 $map
返回没有“isCorrectAnswer”字段的内部答案数组文档。它使用自己的变量来表示元素,以及 $ifNull
的用法。 in 那里只是因为 $map
的“in”部分运算符期望评估每个元素的条件。
总体上更快一些,因为您不必通过 $unwind
和 $group
操作只是为了删除该字段。所以它真的变成了您可能期望的“投影”。
关于mongodb - 转换到第二个嵌套数组中的 "filter"属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24148710/