mongodb - 转换到第二个嵌套数组中的 "filter"属性

标签 mongodb aggregation-framework

好吧,我已经尝试解决这个问题一段时间了,但似乎在原地踏步。

我的主要目标是深入第二个嵌套数组并完全删除“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/

相关文章:

MongoDB > 将新项目添加到数组内的对象中

c# - 用C#聚合$ lookup

javascript - 如何在一次查询中获取多个计数?

javascript - 返回某种类型的有限数量的记录,但返回无限数量的其他记录?

mongodb - 获取数组 mongodb 中的特定字段并作为数组返回

mongodb - 蒙哥界面

node.js - 如果抓取数百万个 URL 并将数据更新到 mongodb,那么 cron 作业服务器是否密集?

javascript - 无法连接 mongoose 和 mockgoose

mongodb - 如何在 mongodb 聚合中将数组元素的子集加在一起?

node.js - 使用node.js将图片保存到mongodb