如何使用聚合确定用户收集了多少积分

How to determine how many points a user has collected using aggregate

我有这个 Schema 结构

const QuizQuestionSchema = new Schema({
  course: { type: String, required: true, trim: true },
  point: { type: Number, required: true, trim: true, min: 1, max: 20 },
  question: { type: String, required: true, trim: true },
  codeBoard: { type: String, default: null, nullable: true },
  answers: { type: [String], required: true, trim: true },
  correctAnswer: { type: String, required: true, trim: true }
});

从客户端我得到文档的数组 ID 和选择的答案 [{id, answer}...]。 我需要找出用户收集了多少分,比较 correctAnswer 和 answer if match add score。如何使用聚合完成此操作?

例子

客户端

[
  { id: "61bc09994da5e9ffe47fccb9", answer: "1 2 4 3 5" },
  { id: "61bc0af14da5e9ffe47fccbb", answer: "1 4 3 2" },
  ...
];

服务器文件

  {
    _id: new ObjectId("61bc09994da5e9ffe47fccb9"),
    course: 'JavaScript',
    point: 10,
    question: 'What will we see in the console ?',
    codeBoard: '...',
    answers: [ '1 2 4 3 5', '1 5 4 3 2', '2 1 4 3 5', '1 5 3 4 2' ],
    correctAnswer: '2 1 4 3 5',
    __v: 0
  },
  {
    _id: new ObjectId("61bc0af14da5e9ffe47fccbb"),
    course: 'JavaScript',
    point: 10,
    question: 'What will we see in the console ?',
    codeBoard: '...',
    answers: [ '1 4 3 2', '1 2 4 3', '1 2 3 4', '1 4 2 3' ],
    correctAnswer: '1 4 3 2',
    __v: 0
  }

您可以使用 $lookup 通过非常简单的管道实现此目的,如下所示:

db.users.aggregate([
  {
    $match: {
      user_id: 1
    }
  },
  {
    "$lookup": {
      "from": "quiz",
      let: {
        quizId: "$id",
        userAnswer: "$answer"
      },
      pipeline: [
        {
          $match: {
            $expr: {
              $and: [
                {
                  $eq: [
                    "$$quizId",
                    "$_id"
                  ]
                },
                {
                  $eq: [
                    "$$userAnswer",
                    "$correctAnswer"
                  ]
                }
              ]
            }
          }
        }
      ],
      "as": "matched"
    }
  },
  {
    $group: {
      _id: null,
      total: {
        $sum: 1
      },
      correct: {
        $sum: {
          $size: "$matched"
        }
      }
    }
  }
])

Mongo Playground

您没有给出所需的确切输入和输出,因此需要进行一些小的更改。

如果客户端发送带有所选答案的字符串中的每个问题 ID,您应该将该数组映射到:

  {
    id: new ObjectId("61bc09994da5e9ffe47fccb9"),
    correctAnswer: "2 1 4 3 5"
  }

记得定义 ObjectId 为:

const ObjectId = require('mongoose').Types.ObjectId;

然后在 $or 运算符中添加完整数组,最后将添加点的每个匹配项分组。

db.collection.aggregate({
  "$match": {
    $or: [
      {
        id: new ObjectId("61bc09994da5e9ffe47fccb9"),
        correctAnswer: "2 1 4 3 5"
      },
      {
        id: new ObjectId("61bc0af14da5e9ffe47fccbb"),
        correctAnswer: "1 4 3 2"
      },
      . . .
    ]
  }
},
{
  "$group": {
    "_id": null, // This means that every document is grouped, because there is no condition to group by
    "points": { 
      $sum: "$point"
    }
  }
})