使用 Express/MongoDB 创建永久链接

Creating permalinks with Express/MongoDB

假设我有以下 LMS 应用程序架构:

const CourseSchema = new mongoose.Schema({
    name: { type: String, required: true },
    code: { type: String, required: true, unique: 1, uppercase: 1 }, // ex. CSCA48
    quizzes: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Quiz' }]
});

const QuizSchema = new mongoose.Schema({
    name: { type: String, required: true }, // ex. 1a
    questions: [{ type: mongoose.Schema.Types.ObjectId, ref: 'Question' }]
});

const QuestionSchema = new mongoose.Schema({
    number: { type: String, required: true }, // ex. 4
    question: { type: String, required: true },
    type: { type: String },
    choices: [String],
    answers: [String]
});

我按照 RESTful API 准则构建(或尝试构建)该应用程序。例如,

GET /courses/[ObjectID]
GET /courses/[ObjectID]/quizzes
GET /courses/[ObjectID]/quizzes/[ObjectID]
GET /courses/[ObjectID]/quizzes/[ObjectID]/questions

我使用 ObjectID 的原因是因为它们是唯一的并且可以轻松检索对象 -- 特别是 app.param()。例如,

router.param('courseID', controllers.Course.getCourseByParam);
router.param('quizID', controllers.Quiz.getQuizByParam);
router.param('questionID', controllers.Question.getQuestionByParam);

router.get('/courses', controllers.Course.getCourses);
router.get('/courses/:courseID', controllers.Course.getCourse);
router.get('/courses/:courseID/quizzes', controllers.Quiz.getQuizzes);
router.get('/courses/:courseID/quizzes/:quizID/questions', controllers.Question.getQuestions);

但是现在,我想知道是否有一种方法可以不使用 ObjectID 来使 URL 更多 friendly/readable?

GET /courses/[code]/quizzes/[name]/questions/[number] 

ex. /courses/CSCA48/quizzes/1a/questions/4 

我对此最担心的是,虽然课程 code 是独一无二的,但测验 name 和问题 number 不是。例如,/courses/CSCA48/quizzes/1b/questions/4 将是不同测验的不同问题。所以,除非我弄错了,否则真的不可能使用 app.param()。因此,我需要以某种方式确保测验属于匹配的课程,然后问题属于匹配的测验。

我并不是真的在寻找代码,只是关于如何处理(或不处理)的大致思路。

由于组合 [code]-[name]-[number] 是唯一的([code] 也是唯一的,这很重要),您应该能够 运行 提出正确问题的查询:

Course.findOne({ code : req.params.code })
      .populate({
        path     : 'quizzes',
        match    : { name : req.params.name },
        populate : {
          path  : 'questions',
          match : { number : req.params.number }
        }
      })

或者,您可以向 QuestionSchema 添加两个字段以反映问题所属的课程和测验,在这种情况下,您只需 运行 一个查询即可找到正确的问题文档(人口需要 3 个查询)。