项目到"过滤"第二个嵌套数组中的属性

时间:2014-06-10 18:49:35

标签: mongodb aggregation-framework

好的,我一直试图解决这个问题,但似乎是在圈子里跑。

我的主要目标是深入第二个嵌套数组并完全删除'isCorrectAnswer'属性...该对象基本上是一个项目,它有2个问题,每个问题有3个答案选项......

在应用程序的“回答”时间范围内,我需要删除'isCorrectAnswer',以便没有用户可以通过查看正在传递的数据来作弊...然后一旦'回答'时间框架已经过去,这将是作为完整对象返回,以向用户指示哪些答案是正确答案。

“item”对象的一个​​示例,其中包含从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课程中学到的知识......

我的第一个目标是进行双重展开,将所有内容展平为单个对象结构。

首先,聚合管道中的步骤是:

{ "$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添加的'_id'属性

感谢您的帮助。

德里克

2 个答案:

答案 0 :(得分:2)

因为你的要求只是"项目"该文件使字段被屏蔽,是的,聚合框架是用于执行此操作的工具。在展开数组和重构时,需要花点时间了解过程。

所以你想要的是:

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,内部$ifNull返回内部答案数组文档而不使用" isCorrectAnswer"领域。它使用它自己的变量来表示元素,而$map的用法只是因为" in" $unwind运算符的一部分期望评估每个元素的条件。

整体速度要快一些,因为您不必通过$group和{{3}}操作来删除字段。所以它真的变成了"投影"你可能会期待的。

答案 1 :(得分:0)

您可以使用 $ unset 运算符,结合点表示法来删除属性。

例如,以下命令将从第一个答案数组中删除isCorrectAnswer属性:

db.collectionname.update({_ ID:" SOME_ID"},{$取消设置:{" questions.0.answers.0.isCorrectAnswer":"&# 34;}})