【问题标题】:Mongoose group by an lookup with nested arrays通过嵌套数组查找猫鼬组
【发布时间】:2021-10-17 22:50:13
【问题描述】:

我有两个模式,第一个是 Quiz,另一个是 quizResults,我想在 quiz Schema 中查找时从 quizResult 中获取聚合数据。以下是我的测验模式:

vidId: {type: Number, required: true},
status: {type: Number,  enum: [statusType.quizStatusEnums.LIVE, statusType.quizStatusEnums.DELETED], default: statusType.quizStatusEnums.LIVE},
questions: [
    {
        questionNum: { type: Number },
        questionName: { type: String },
        answers: [
            {
                answerId: { type: String, default: uuid.v4() },
                answerName: { type: String },
                isCorrect: { type: Boolean },
                answerType: { type: Number,  enum: [statusType.quizTypeEnums.QUIZ, statusType.quizTypeEnums.SURVEY], default: statusType.quizTypeEnums.QUIZ},
                hotspotId: { type: Number },
                overlayId: {type: Number},
                panelId: {type: String}
            }
        ]
    }
],

第二个是QuizResults:需要对这个集合进行聚合查询。

  created: {
    type: Date,
},
vidId: {
    type: Number,
    required: true,
},
viewerId: {
    type: String,
    required: true,
},
quizId: {
    type: Schema.Types.ObjectId,
    ref: 'quiz'
},
questionId: {
    type: Schema.Types.ObjectId,
    ref: 'quiz'
},
answerId: {
    type: String,
    required: true
},
isCorrect: {
    type: Boolean,
    default: false,
},
whenAnswered: {
    type: Date
},

我想要这样的最终聚合结果:

  [
{
  "questionNum": 2,
  "questionName": "Which is the best selling record in history ?",
  "correct": 10,
  "incorrect": 20,
  "totalAnswers": 30,
  "answers": [
    {
      "answerId": "123abc",
      "answerName": "Thriller Michel Jackson",
      "numResponses": 10
    },
    {
      "answerId": "234d",
      "answerName": "A kind of Magic Queen",
      "numResponses": 10
    },
    {
      "answerId": "432e",
      "answerName": "help The Beatles",
      "numResponses": 10
    }
  ]
},
{
  "questionNum": 1,
  "questionName": "What value has the number PI?",
  "correct": 5,
  "incorrect": 3,
  "totalAnswers": 8,
  "answers": [
    {
      "answerId": "111",
      "answerName": "3.12",
      "numResponses": 0
    },
    {
      "answerId": "222",
      "answerName": "3.14",
      "numResponses": 5
    },
    {
      "answerId": "333",
      "answerName": "3.16",
      "numResponses": 3
    }
  ]
}
 ]

我尝试的是:

    aggregate([
        { "$match": { "vidId": 8225342, } },
        {
            "$group": {
                "_id": "$questionId",
            
                "Correct": {
                    "$sum": {
                        "$cond": [
                            { "$eq": ["$isCorrect", true] },
                            1,
                            0
                        ]
                    },
                },
                "Incorrect": {
                    "$sum": {
                        "$cond": [
                            { "$eq": ["$isCorrect", false] },
                            1,
                            0
                        ]
                    }
                },
            }
        },
        {
            "$lookup": {
                "from": "quiz",
                "let": { "id": "$_id" },
                "pipeline": [
                    { "$match": { "$expr": { "$in": ["$$id", "$questions._id"] } } },
                    { "$unwind": "$questions" },
                    { "$match": { "$expr": { "$eq": ["$questions._id", "$$id"] } } },

                ],
                "as": "quizData"
            }
        },

        { $unwind: '$quizData' },
        
        { "$project": {
            "questionName": "$quizData.questions.questionName", 
        "questionNum": "$quizData.questions.questionNum",
        "Correct": "$Correct",
        "Incorrect": "$Incorrect", 
        "answers": "$quizData.questions.answers" } },
    ])

我得到了类似的结果:

    {
    "_id": "611632305bd3910929b95552",
    "questionName": "Which is the best selling record in history?",
    "questionNum": 5,
    "Correct": 3,
    "Incorrect": 0,
    "answers": [
        {
            "answerId": "078f441b-373f-40e9-89e1-04fca0a9fc5d",
            "answerType": 0,
            "_id": "611632305bd3910929b95553",
            "answerName": "Thriller Michel Jackson",
            "isCorrect": true,
            "hotspotId": 470114,
            "overlayId": 3,
            "panelId": "12abc"
        },
        {
            "answerId": "644b80fe-5778-46fa-b3a6-1eff5989cdee",
            "answerType": 0,
            "_id": "611632305bd3910929b95554",
            "answerName": "A kind of Magic Queen",
            "isCorrect": false,
            "hotspotId": 470113,
            "overlayId": 4,
            "panelId": "12345abc"
        },
        {
            "answerId": "5bde2682-66fe-4c79-a728-aea67f6842a8",
            "answerType": 0,
            "_id": "611632305bd3910929b95555",
            "answerName": "help The Beatles",
            "isCorrect": false,
            "hotspotId": 470112,
            "overlayId": 3,
            "panelId": "12abc"
        }
    ]
},

我怎样才能得到这样的 Answers 数组:

 answers: [
                {
                    answerId: "123abc",
                    answerName: "Thriller Michel Jackson",
                    numResponses: 10
                },  
                 {
                    answerId: "234d",
                    answerName: "A kind of Magic Queen",
                    numResponses: 10
                },
                {
                    answerId: "432e",
                    answerName: "help The Beatles",
                    numResponses: 10
                }
]

         

【问题讨论】:

    标签: javascript mongodb mongoose aggregation-framework aggregation


    【解决方案1】:

    您可以尝试反过来处理它。使用$lookupquizResults 进行过滤和聚合,然后运行$map$filter 以获得每个答案的匹配统计信息:

    db.quiz.aggregate([
        {
            $match: { "vidId": 8225342 }
        },
        {
            $lookup: {
                from: "quizResults",
                pipeline: [
                    { $match: { "vidId": 8225342 } },
                    {
                        $group: {
                            _id: "$answerId",
                            count: { $sum: 1 }
                        }
                    }
                ],
                as: "quizResults"
            }
        },
        {
            $project: {
                _id: 1,
                questions: {
                    $map: {
                        input: "$questions",
                        as: "q",
                        in: {
                            _id: "$$q._id",
                            questionName: "$$q.questionName",
                            questionNum: "$$q.questionNum",
                            answers: {
                                $map: {
                                    input: "$$q.answers",
                                    as: "a",
                                    in: {
                                        $mergeObjects: [
                                            "$$a",
                                            {
                                                $let: {
                                                    vars: {
                                                        fst: {
                                                            $first: { 
                                                                $filter: { input: "$quizResults", cond: { $eq: [ "$$this._id", "$$a._id" ] } }
                                                            } 
                                                        }
                                                    },
                                                    in: { numResponses: "$$fst.count" }
                                                }
                                            }
                                        ]
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    ])
    

    Mongo Playground

    【讨论】:

    • 我刚刚更新了我的问题,我期待答案数组包含每个答案的总和,每个答案给出了多少次。
    • @BilalMaher 您能否使用您的一些示例数据创建一个 Mongo Playground 以获得预期结果?
    • 感谢您的评论我已经创建了一个 mongo 游乐场:mongoplayground.net/p/E4_0WYh3hpW
    • @BilalMaher 谢谢你,这真的很有帮助,修改了我的答案
    • 非常感谢您提出该查询,请您添加工作的 mongo 游乐场。我无法运行您在此处粘贴的查询。
    猜你喜欢
    • 2023-01-30
    • 2018-02-02
    • 2018-10-30
    • 2021-05-06
    • 2021-08-08
    • 2019-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多