如何在 mongoDB 中取消嵌套和分组集合

How to un-nest and group collections in mongoDB

我不明白如何在 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',
      },
    },
  ])

此语句的return如下:

{
    "_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 字段匹配的相应问题下。

提前致谢!

更新 基于评论:

更新查询:

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

旧查询:

注意:请修正 collection 名称 and/or 字段名称。试试这个查询:

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 collection

{
    "_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 collection:

/* 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
        }
    ]
}