通过嵌套数组查找猫鼬组

Posted

技术标签:

【中文标题】通过嵌套数组查找猫鼬组【英文标题】: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
                
]

         

【问题讨论】:

【参考方案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 游乐场。我无法运行您在此处粘贴的查询。

以上是关于通过嵌套数组查找猫鼬组的主要内容,如果未能解决你的问题,请参考以下文章

如何通过猫鼬中的嵌套属性查找

如何更新猫鼬嵌套数组文档[重复]

使用没有数组的嵌套文档为我的 JSON 定义有效的猫鼬模式?

猫鼬无法通过“field.attributes”进行嵌套搜索

通过在嵌套的对象数组中查找多个条件来过滤数组

猫鼬嵌套查找不起作用[重复]