Мангуст группируется путем поиска с вложенными массивами

#javascript #mongodb #mongoose #aggregation-framework #aggregation

Вопрос:

У меня есть две схемы , первая-викторина, а вторая-результаты викторины, я хочу получить агрегированные данные из результатов викторины при выполнении поиска в схеме викторины. Ниже приведена моя схема викторины:

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

Второй — это результаты опроса: Запрос агрегирования необходимо выполнить для этой коллекции.

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

What I tried is :

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

I got the results something like that:

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

Вы можете попытаться подойти к этому с другой стороны. Используйте $lookup для quizResults фильтрации и агрегирования, а затем запустите $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" }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    }
                }
            }
        }
    }
])
 

Игровая площадка Монго

Комментарии:

1. Я только что обновил свой вопрос, я ожидаю массив ответов с суммой каждого ответа, сколько раз был дан каждый ответ.

2. @BilalMaher смогли бы вы создать игровую площадку Mongo с небольшим количеством ваших выборочных данных для ожидаемого результата?

3. Спасибо за ваш комментарий, я создал игровую площадку для монго: mongoplayground.net/p/E4_0WYh3hpW

4. @BilalMaher спасибо, это было действительно полезно, изменил мой ответ

5. Большое вам спасибо за этот запрос, не могли бы вы, пожалуйста, добавить рабочую игровую площадку mongo. Я не могу выполнить запрос, который вы вставили сюда.