#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. Я не могу выполнить запрос, который вы вставили сюда.