投影到“过滤”项目第二个嵌套数组中的属性 [英] Project to "filter" property within second nested array

查看:53
本文介绍了投影到“过滤”项目第二个嵌套数组中的属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好吧,我已经尝试解决了一段时间,但似乎正在运行。

OK I have been trying to tackle this for a while now but seem to be running in circles.

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

My main goal is to dive into the 2nd nested array and remove the 'isCorrectAnswer' property completely... The object is basically an item, which has 2 questions, which each have 3 answer options...

在'answering应用程序的时间范围,我需要删除 isCorrectAnswer,以便没有用户可以通过查看正在传递的数据来作弊...然后,一旦答案时间范围过去,它将作为完整对象返回以表明

During the 'answering' timeframe of the app, I need to remove the 'isCorrectAnswer' so that no users can cheat by looking into the data being passed... Then once the 'answering' timeframe has passed, this will be returned as the complete object to indicate to the user which answers were the correct ones.

MongoDB返回的带有 item对象的问题和答案的示例是:

An example of the 'item' object with it's questions and answers being returned from MongoDB is:

{
    "_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课程中学到的知识...

Now, based on what I have learned from the MongoDB course...

我的第一个目标是进行两次

My first goal was to do a double unwind to flatten everything out into single object structures.

因此,聚合管道的第一步是:

So first to steps in the aggregation pipeline are:

{ "$unwind": "$questions" },
{ "$unwind": "$questions.answers" }

这很好...

我的下一步是运行$ project删除'isCorrectAnswer'属性:

My next step was to run $project to remove the 'isCorrectAnswer' property:

   { "$project": {
       "_id":1,
       "name":1,
       "description":1,
       "questions":{
           "_id":"$questions._id",
           "question":"$questions.question",
           "answers":{
               "_id":"$questions.answers._id",
               "answer":"$questions.answers.answer"
           }
       }
   }}

这也可以正常工作...

This works fine as well...

现在我所欠缺的是将对象组合回再次进入原始结构(没有'isCorrectAnswer'属性)...

Now where I am falling short is combining the object back together again into the ORIGINAL STRUCTURE (without the 'isCorrectAnswer' property)...

我可以在管道中的下一个位置运行此$ group命令,但确实可以没有将他们的问题归类

I can run this $group command next in the pipeline, which DOES work but the answers are not grouped back in with their question

   { "$group":{
       "_id":{
           "_id":"$_id",
           "ordinal":"$ordinal",
           "name":"$name",
           "description":"$description",
           "benefits":"$benefits",
           "specialOffer":"$specialOffer",
           "choicePoints":"$choicePoints",
           "bonusPoints":"$bonusPoints",
           "redemptionPoints":"$redemptionPoints",
           "questions":"$questions"
       }
   }}

我仍在掌握聚合框架,而更多地与$ group命令有关...我想知道是否有任何我应该做的不同的步骤或如何运行第二个$ group

I am still grasping the aggregation framework and more to do with the $group command... I am wondering if there are any steps I should be doing differently or how to run a 2nd $group to combine the 'answers' together.

我还假定我将需要运行最终的$ project来清理通过$ group添加的'_id'属性

I also assume I will need to run a final $project to clean up the '_id' properties that are getting added via the $group

感谢您的帮助。

Derek

推荐答案

由于您的要求是仅投影文档,以便屏蔽字段,因此,聚合框架是执行此操作的工具。展开数组并重构时,需要花点时间来解决这个问题。

Since your requirement is to just "project" the document so the field is masked, yes the aggregation framework is a tool for doing this. It takes a bit to get your head around the process when unwinding arrays and reconstructing though.

所以您想要的是:

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 <与数组一起使用的strong> $ map 运算符:

But really, if you have a MongoDB 2.6 or greater version then you do not need to $unwind and $group the results back together in order to omit that field. You can now just do this using $project and the $map operator which works with arrays:

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
                    ]
                }
            }
        }
    }}
])

很抱歉缩进在页面上滚动了一点,但相比之下仍然更易于阅读。

Sorry for the indentation scrolling off the page a little there, but it is still easier to read by comparison.

第一个 $ map 处理plac中的问题数组e并输入到内部 $ map ,它返回内部答案数组文档,而没有 isCorrectAnswer字段。它使用自己的变量表示元素,并使用 $ ifNull 只是因为 $ map 运算符希望评估每个条件

The first $map processes the questions array in place and feeds to an inner $map that returns the inner answers array documents without the "isCorrectAnswer" field. It uses it's own variables to represent the elements, and the usage of $ifNull in there is just because the "in" part of the $map operator expects to evaluate a condition on each of those elements.

总体上要快一点,因为您不必通过 $ unwind $ group 操作只是为了删除字段。因此,它实际上只是您可能期望的投影。

Overall a bit faster, as you do not have to go through the $unwind and $group operations just to remove the field. So it really becomes just the "projection" that you might expect.

这篇关于投影到“过滤”项目第二个嵌套数组中的属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆