【问题标题】:How to un-nest and group collections in mongoDB如何在 mongoDB 中取消嵌套和分组集合
【发布时间】:2021-06-18 12:32:54
【问题描述】:

我不明白如何在 mongoDB 中展开然后嵌套集合。基本上我有两个结构如下的集合:

问题文档:

{
    "_id" : 1,
    "questions" : [
        {
            "_id" : 1,
            "body" : "What fabric is the top made of?",
            "date_written" : "2018-01-04",
            "asker_name" : "yankeelover",
            "asker_email" : "first.last@gmail.com",
            "reported" : 0,
            "helpful" : 2
        },
        {
            "_id" : 2,
            "body" : "HEY THIS IS A WEIRD QUESTION!!!!?",
            "date_written" : "2019-04-28",
            "asker_name" : "jbilas",
            "asker_email" : "first.last@gmail.com",
            "reported" : 1,
            "helpful" : 4
        },
        {
            "_id" : 4,
            "body" : "How long does it last?",
            "date_written" : "2019-07-06",
            "asker_name" : "funnygirl",
            "asker_email" : "first.last@gmail.com",
            "reported" : 0,
            "helpful" : 6
        },

答案文档:

{
    "_id" : 1,
    "answers" : [
        {
            "_id" : 8,
            "body" : "DONT BUY IT! It's bad for the environment",
            "date_written" : "2018-01-04",
            "answerer_name" : "metslover",
            "answerer_email" : "first.last@gmail.com",
            "reported" : 0,
            "helpful" : 8
        },
        {
            "_id" : 7,
            "body" : "Its the best! Seriously magic fabric",
            "date_written" : "2018-01-04",
            "answerer_name" : "metslover",
            "answerer_email" : "first.last@gmail.com",
            "reported" : 0,
            "helpful" : 7
        },
        {
            "_id" : 5,
            "body" : "Something pretty soft but I can't be sure",
            "date_written" : "2018-01-04",
            "answerer_name" : "metslover",
            "answerer_email" : "first.last@gmail.com",
            "reported" : 0,
            "helpful" : 5,
            "photos" : [
                {
                    "_id" : 1,
                    "url" : "https://images.unsplash.com/photo-1530519729491-aea5b51d1ee1?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1651&q=80"
                },

答案文档中的 _id 字段与作为答案的问题的 _id 字段相匹配。

最终目标是获得如下所示的数据:

{
    "_id": "17762",
    "questions": [
        {
            "question_id": 152829,
            "question_body": "Why Does it look like this?",
            "question_date": "2021-03-06T00:00:00.000Z",
            "asker_name": "garethTheGreato",
            "question_helpfulness": 60,
            "reported": false,
            "answers": {
                "1443770": {
                    "id": 1443770,
                    "body": "This question was really helpful! Thank you.",
                    "date": "2021-03-09T00:00:00.000Z",
                    "answerer_name": "SatisfiedCustomer",
                    "helpfulness": 3,
                    "photos": []
                },
                "1443807": {
                    "id": 1443807,
                    "body": "mimk",
                    "date": "2021-03-09T00:00:00.000Z",
                    "answerer_name": "jij",
                    "helpfulness": 3,
                    "photos": [
                        "blob:http://localhost:3000/8f6375b3-0795-4210-bef7-f112feed8244"
                    ]
                },
                "1443834": {
                    "id": 1443834,
                    "body": "10/10 would recomend.",
                    "date": "2021-03-09T00:00:00.000Z",
                    "answerer_name": "Krista",
                    "helpfulness": 2,
                    "photos": []
                },
                "1443845": {
                    "id": 1443845,
                    "body": "Thank you so much for playing my game!",
                    "date": "2021-03-10T00:00:00.000Z",
                    "answerer_name": "itsameemario",
                    "helpfulness": 1,
                    "photos": []
                },
                "1443880": {
                    "id": 1443880,
                    "body": "Tree",
                    "date": "2021-03-10T00:00:00.000Z",
                    "answerer_name": "Tree",
                    "helpfulness": 0,
                    "photos": [
                        "blob:http://localhost:3000/123051b6-4dfb-410a-a96f-d4a5128e3056"
                    ]
                }
            }
        },
        {
            "question_id": 152702,
            "question_body": "Please write your question here",
            "question_date": "2021-03-05T00:00:00.000Z",
            "asker_name": "Your nickname",
            "question_helpfulness": 32,
            "reported": false,
            "answers": {}
        },

我遇到的问题是,当我运行查找时,我得到了一个与问题集合相关的答案数组,但由于答案深深嵌套,我不确定如何获得他们特定问题的每组答案.

这是我目前所拥有的:(暂时忽略切片和排序,这些是我稍后作为项目的另一部分需要用到的参数)

  db.prodquests.aggregate([
    { $match: { _id: 5 } },
    { $unwind: '$questions' },
    { $match: { 'questions.reported': { $lt: 1 } } },
    { $sort: { 'questions.helpful': -1 } },
    { $group: { _id: '$_id', questions: { $push: '$questions' } } },
    { $project: { _id: 1, questions: { $slice: ['$questions', 0, 1] } } },
    { $unwind: '$questions' },
    {
      $lookup: {
        from: 'groupansphotos',
        localField: 'questions._id',
        foreignField: '_id',
        as: 'answers',
      },
    },
  ])

这条语句的返回如下:

{
    "_id" : 5,
    "questions" : {
        "_id" : 37,
        "body" : "Why is this product cheaper here than other sites?",
        "date_written" : "2018-10-18",
        "asker_name" : "willsmith",
        "asker_email" : "first.last@gmail.com",
        "reported" : 0,
        "helpful" : 4
    },
    "answers" : [
        {
            "_id" : 37,
            "answers" : [
                {
                    "_id" : 68,
                    "body" : "We are selling it here without any markup from the middleman!",
                    "date_written" : "2018-08-18",
                    "answerer_name" : "Seller",
                    "answerer_email" : "null",
                    "reported" : 0,
                    "helpful" : 4
                }
            ]
        }
    ]
}

本质上,我只想将答案数组分组到 _id 字段匹配的相应问题下。

提前谢谢你!

【问题讨论】:

    标签: database mongodb mongoose aggregation-framework document-database


    【解决方案1】:

    更新基于 cmets:

    更新查询:

    db.questions.aggregate([
        { $match: { _id: 5 } },
        { $unwind: '$questions' },
        { $match: { 'questions.reported': { $lt: 1 } } },
        { $sort: { 'questions.helpful': -1 } },
        {
            $lookup: {
                from: "answers",
                let: { question_id: "$questions._id" },
                pipeline: [
                    {
                        $match: {
                            $expr: { $eq: ["$_id", "$$question_id"] }
                        }
                    },
                    { $unwind: "$answers" },
                    {
                        $project: {
                            _id: 0,
                            k: { $toString: "$answers._id" },
                            v: "$$ROOT.answers"
                        }
                    }
                ],
                as: "answers"
            }
        },
        {
            $group: {
                _id: "$_id",
                questions: {
                    $push: {
                        question_id: "$questions._id",
                        question_body: "$questions.body",
                        question_date: "$questions.date_written",
                        asker_name: "$questions.asker_name",
                        question_helpfulness: "$questions.helpful",
                        reported: "$questions.reported",
                        answers: { $arrayToObject: "$answers" }
                    }
                }
            }
        }
    ]);
    

    旧查询:

    注意:请修正集合名称和/或字段名称。试试这个查询:

    db.questions.aggregate([
        { $match: { _id: 5 } },
        { $unwind: '$questions' },
        { $match: { 'questions.reported': { $lt: 1 } } },
        { $sort: { 'questions.helpful': -1 } },
        {
            $lookup: {
                from: "answers",
                let: { question_id: "$questions._id" },
                pipeline: [
                    {
                        $match: {
                            $expr: { $eq: ["$_id", "$$question_id"] }
                        }
                    },
                    { $unwind: "$answers" },
                    {
                        $project: {
                            _id: 0,
                            k: { $toString: "$answers._id" },
                            v: "$$ROOT.answers"
                        }
                    }
                ],
                as: "answers"
            }
        },
        {
            $match: {
                $expr: {
                    $gt: [{ $size: "$answers" }, 0]
                }
            }
        },
        {
            $group: {
                _id: "$_id",
                questions: {
                    $push: {
                        question_id: "$questions._id",
                        question_body: "$questions.body",
                        question_date: "$questions.date_written",
                        asker_name: "$questions.asker_name",
                        question_helpfulness: "$questions.helpful",
                        reported: "$questions.reported",
                        answers: { $arrayToObject: "$answers" }
                    }
                }
            }
        }
    ]);
    

    输出:

    {
        "_id" : 5,
        "questions" : [
            {
                "question_id" : 2,
                "question_body" : "HEY THIS IS A WEIRD QUESTION!!!!?",
                "question_date" : "2019-04-28",
                "asker_name" : "jbilas",
                "question_helpfulness" : 4,
                "reported" : 0,
                "answers" : {
                    "14" : {
                        "_id" : 14,
                        "body" : "DONT BUY IT! It's bad for the environment",
                        "date_written" : "2018-01-04",
                        "answerer_name" : "metslover",
                        "answerer_email" : "first.last@gmail.com",
                        "reported" : 0,
                        "helpful" : 8
                    },
                    "15" : {
                        "_id" : 15,
                        "body" : "Its the best! Seriously magic fabric",
                        "date_written" : "2018-01-04",
                        "answerer_name" : "metslover",
                        "answerer_email" : "first.last@gmail.com",
                        "reported" : 0,
                        "helpful" : 7
                    },
                    "16" : {
                        "_id" : 16,
                        "body" : "Something pretty soft but I can't be sure",
                        "date_written" : "2018-01-04",
                        "answerer_name" : "metslover",
                        "answerer_email" : "first.last@gmail.com",
                        "reported" : 0,
                        "helpful" : 5
                    }
                }
            },
            {
                "question_id" : 1,
                "question_body" : "What fabric is the top made of?",
                "question_date" : "2018-01-04",
                "asker_name" : "yankeelover",
                "question_helpfulness" : 2,
                "reported" : 0,
                "answers" : {
                    "11" : {
                        "_id" : 11,
                        "body" : "DONT BUY IT! It's bad for the environment",
                        "date_written" : "2018-01-04",
                        "answerer_name" : "metslover",
                        "answerer_email" : "first.last@gmail.com",
                        "reported" : 0,
                        "helpful" : 8
                    },
                    "12" : {
                        "_id" : 12,
                        "body" : "Its the best! Seriously magic fabric",
                        "date_written" : "2018-01-04",
                        "answerer_name" : "metslover",
                        "answerer_email" : "first.last@gmail.com",
                        "reported" : 0,
                        "helpful" : 7
                    },
                    "13" : {
                        "_id" : 13,
                        "body" : "Something pretty soft but I can't be sure",
                        "date_written" : "2018-01-04",
                        "answerer_name" : "metslover",
                        "answerer_email" : "first.last@gmail.com",
                        "reported" : 0,
                        "helpful" : 5
                    }
                }
            }
        ]
    }
    

    测试数据:

    questions收藏

    {
        "_id" : 5,
        "questions" : [
            {
                "_id" : 1,
                "body" : "What fabric is the top made of?",
                "date_written" : "2018-01-04",
                "asker_name" : "yankeelover",
                "asker_email" : "first.last@gmail.com",
                "reported" : 0,
                "helpful" : 2
            },
            {
                "_id" : 2,
                "body" : "HEY THIS IS A WEIRD QUESTION!!!!?",
                "date_written" : "2019-04-28",
                "asker_name" : "jbilas",
                "asker_email" : "first.last@gmail.com",
                "reported" : 0,
                "helpful" : 4
            },
            {
                "_id" : 4,
                "body" : "How long does it last?",
                "date_written" : "2019-07-06",
                "asker_name" : "funnygirl",
                "asker_email" : "first.last@gmail.com",
                "reported" : 0,
                "helpful" : 6
            }
        ]
    }
    

    answers收藏:

    /* 1 */
    {
        "_id" : 1,
        "answers" : [
            {
                "_id" : 11,
                "body" : "DONT BUY IT! It's bad for the environment",
                "date_written" : "2018-01-04",
                "answerer_name" : "metslover",
                "answerer_email" : "first.last@gmail.com",
                "reported" : 0,
                "helpful" : 8
            },
            {
                "_id" : 12,
                "body" : "Its the best! Seriously magic fabric",
                "date_written" : "2018-01-04",
                "answerer_name" : "metslover",
                "answerer_email" : "first.last@gmail.com",
                "reported" : 0,
                "helpful" : 7
            },
            {
                "_id" : 13,
                "body" : "Something pretty soft but I can't be sure",
                "date_written" : "2018-01-04",
                "answerer_name" : "metslover",
                "answerer_email" : "first.last@gmail.com",
                "reported" : 0,
                "helpful" : 5
            }
        ]
    },
    
    /* 2 */
    {
        "_id" : 2,
        "answers" : [
            {
                "_id" : 14,
                "body" : "DONT BUY IT! It's bad for the environment",
                "date_written" : "2018-01-04",
                "answerer_name" : "metslover",
                "answerer_email" : "first.last@gmail.com",
                "reported" : 0,
                "helpful" : 8
            },
            {
                "_id" : 15,
                "body" : "Its the best! Seriously magic fabric",
                "date_written" : "2018-01-04",
                "answerer_name" : "metslover",
                "answerer_email" : "first.last@gmail.com",
                "reported" : 0,
                "helpful" : 7
            },
            {
                "_id" : 16,
                "body" : "Something pretty soft but I can't be sure",
                "date_written" : "2018-01-04",
                "answerer_name" : "metslover",
                "answerer_email" : "first.last@gmail.com",
                "reported" : 0,
                "helpful" : 5
            }
        ]
    }
    

    【讨论】:

    • 这正是我想要的,非常感谢!在查找阶段拥有管道似乎非常强大,我希望像你一样掌握它。
    • 我们不能从$lookup 阶段内部执行此操作。从外部,我们可以在连接操作产生的字段上使用$unwind,以从外部/本地集合中排除文档,但在您的情况下,我们不能使用$unwind,因为我们需要该数组将其转换为对象。
    • 对不起,我应该更清楚。现在,当我对所选问题执行联接时,如果问题没有匹配的答案文档,则将从最终结果中删除。我想包括在查找之前从原始匹配阶段返回的所有问题,如果它们存在的话,则与他们的答案一起加入
    • 我已经更新了答案。检查它是否有帮助。刚刚删除了$group 之前的$match 阶段。
    • 哇,这是一个非常简单的修复。我现在可以看到那肯定是看错了问题。非常感谢您的帮助!!!
    猜你喜欢
    • 2021-04-19
    • 2018-03-06
    • 1970-01-01
    • 2021-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多