Search code examples
node.jsmongodbmongooseorm

MongoDB schema design for multpile choice questions and answers


I'm not skilled in MongoDB designing and I need help in designing a DB. What is the best structure for Storing Questions having answer choices and Answers from candidate?

-Each candidate will get a set of 12 questions if the candidate fails in the first exam they can attend 2 more exams. So on each exam candidate should get different set of questions each time.

-Answer by each candidate for each test will have to be recorded with the score out of 12 as each question set is 12.


Solution

  • I have created a mongoose schema for each required details. You can take help from it. I have analyzed a bit your requirements and adding models for many schemas, first question schema, exported as a model

    import { Schema } from 'mongoose';
    import { AnswerOptionSchema } from './answer-option-schema';
    const mongoose = require('mongoose');
    
    export const QuestionSchema: Schema = new Schema({
      question: {
        type: String,
        minlength: 10,
        maxlength: 1000,
      },
      answerOptions: {
        type: [AnswerOptionSchema],
        default: undefined,
        validate: {
          validator: function(value: any) {
            return value && value.length === 4;
          },
          message: 'Answer options should be 4.'
        }
      }
    }, {
      timestamps: true
    });
    
    export const Question = mongoose.model('Question', QuestionSchema);
    

    and here in the QuestionSchema, I have embedded an AnswerOptionSchema as

    import { Schema } from 'mongoose';
    
    export const AnswerOptionSchema: Schema = new Schema({
      optionNumber: {
        type: Number
      },
      answerBody: {
        type: String,
        minlength: 1,
        maxlength: 200,
      },
      isCorrectAnswer: { // you can store the correct answer with question id in another model.
        type: Boolean,
        default: false
      }
    }, {
      _id: false
    });
    

    With the help of these schemas, I have created a QuestionSetSchema to add a set of question schema as

    import { Schema } from "mongoose";
    import { QuestionSchema } from "./question-schema";
    const mongoose = require('mongoose');
    
    export const QuestionSetSchema: Schema = new Schema({
      questionSet: {
        type: [QuestionSchema],
        validate: {
          validator: function(value: any) {
            return value.length === 12;
          },
          message: 'Question set must be 12.'
        }
      },
    }, {
      timestamps: true
    });
    
    export const QuestionSet = mongoose.model('QuestionSet', QuestionSetSchema);
    

    Now prepared with the question, answer options and the set, now need to design the candidate schema,

    import { Schema } from "mongoose";
    const mongoose = require('mongoose');
    
    export const CandidateSchema: Schema = new Schema({
      name: String,
      email: String, // you can store other candidate related information here.
      totalAttempt: {
        type: Number,
        default: 0,
        validate: {
          validator: function(value: number) {
            return value === 3;
          },
          message: 'You have already done three attempts.'
        }
      },
      candidateQuestionAnswers: {
        type: [Schema.Types.ObjectId],
        ref: 'CandidateQuesAnswer'
      }
    }, {
      timestamps: true
    });
    
    export const Candidate = mongoose.model('Candidate', CandidateSchema);
    

    Here, you will notice, I am also calculating the totalAttempt of the candidate and the answers for each set given by him in the CandidateQuesAnswer model. This model has the structure like

    import { Schema } from "mongoose";
    
    export const CandidateQuesAnswerSchema = new Schema({
      candidate: {
        type: Schema.Types.ObjectId,
        ref: 'Candidate'
      },
      questionSet: {
        type: Schema.Types.ObjectId,
        ref: 'QuestionSet'
      },
      questionAnswers: {
        type: [Number] // You can add answer schema
      },
      totalScore: {
        type: Number
      },
      isPassed: {
        type: Boolean,
        default: false
      }
    }, {
      timestamps: true
    });
    
    CandidateQuesAnswerSchema.pre('save', function updateTotalScore(next) {
      // update total score of the candidate here based on the correct questionAnswers and
      // questionSet.
      next();
    });
    
    CandidateQuesAnswerSchema.pre('save', function updateIsPassed(next) {
      // update the isPassed based on the totalScore obtained by the candidate.
      next();
    });
    
    export const CandidateQuesAnswer = mongoose.model('CandidateAnswer', CandidateQuesAnswerSchema);
    

    Where I have used pre save hooks provided by mongoose, before saving the document and calculating the values to declare the candidate pass or fail.