'How to Access a Field in Array of Objects With Joi Fork Method?

I am trying to write a reusable validation schema and I can change the rules of fields if I need it. I do this using a method called a fork. However, this time I couldn't imagine how can I access and change the rule of an object inside of an array. In some cases, some fields must be required. So I call the changed schema the default schema with the validation method. I am using this solution for a few models and generally, it works perfectly. Can you help me to imagine how can I solve this problem?

In this model, I have a subdocument field. This field is an array of objects field. That's why I have 2 different schemas. When the create method calls, I just need the title, description, and category object fields. If a user wants to add a question to the quiz record, I need a question array.

I was thinking that I can write a validator for only the question schema but if I don't add a field to the quiz validation schema then joi throws an error with the message "ABC field not allowed". I'm stuck because of this situation and I can't continue.

Quiz Model and Validation Schema and Method

const Joi = require('joi');
const mongoose = require('mongoose');
const slugCreator = require('mongoose-slug-updater');
mongoose.plugin(slugCreator);

const QuestionSchema = mongoose.Schema({
    questionText: {
        type: String,
        trim: true,
        minLength: 10
    },
    firstChoiceText: {
        type: String,
        trim: true,
        minLength: 1
    },
    firstChoiceIsTrue: {
        type: Boolean
    },
    secondChoiceText: {
        type: String,
        trim: true,
        minLength: 1
    },
    secondChoiceIsTrue: {
        type: Boolean
    },
    thirdChoiceText: {
        type: String,
        trim: true,
        minLength: 1
    },
    thirdChoiceIsTrue: {
        type: Boolean
    },
    fourthChoiceText: {
        type: String,
        trim: true,
        minLength: 1
    },
    fourthChoiceIsTrue: {
        type: Boolean
    }
}, { timestamps: true });

const QuizSchema = mongoose.Schema({
    title: {
        type: String,
        required: true,
        trim: true,
        minLength: 15,
        maxLength: 250
    },
    description: {
        type: String,
        requried: true,
        trim: true,
        minLength: 50
    },
    coverImage: {
        type: String,
        trim: true
    },
    slug: {
        type: String,
        unique: true,
        trim: true,
        slug: ['title'],
        slugPaddingSize: 3
    },
    category: {
        title: {
            type: String,
            trim: true,
            required: true
        },
        categoryId: {
            type: mongoose.Types.ObjectId,
            trim: true,
            required: true
        },
        slug: {
            type: String,
            trim: true,
            required: true
        }
    },
    questions: [QuestionSchema],
    createdBy: {
        userId: {
            type: mongoose.Types.ObjectId,
            required: true
        },
        fullName: {
            type: String,
            required: true,
            trim: true
        },
        email: {
            type: String,
            required: true,
            trim: true
        }
    },
    updatedBy: {
        userId: {
            type: mongoose.Types.ObjectId,
            required: true
        },
        fullName: {
            type: String,
            required: true,
            trim: true
        },
        email: {
            type: String,
            required: true,
            trim: true
        }
    }
}, { collection: 'quizzes', timestamps: true });

const validationSchema = {
    title: Joi.string().trim().min(15).max(250),
    description: Joi.string().trim().min(50),
    coverImage: Joi.string().trim(),
    slug: Joi.string().trim(),
    category: {
        title: Joi.string().trim(),
        categoryId: Joi.string().trim(),
        slug: Joi.string().trim()
    },
    questions: Joi.array().items(
        Joi.object({
            questionText: Joi.string().trim().min(10),
            firstChoiceText: Joi.string().trim().min(1),
            firstChoiceIsTrue: Joi.boolean(),
            secondChoiceText: Joi.string().trim().min(1),
            secondChoiceIsTrue: Joi.boolean(),
            thirdChoiceText: Joi.string().trim().min(1),
            thirdChoiceIsTrue: Joi.boolean(),
            fourthChoiceText: Joi.string().trim().min(1),
            fourthChoiceIsTrue: Joi.boolean(),
        })
    ),
    createdBy: {
        userId: Joi.string().trim(),
        fullName: Joi.string().trim(),
        email: Joi.string().email().trim()
    },
    updatedBy: {
        userId: Joi.string().trim(),
        fullName: Joi.string().trim(),
        email: Joi.string().email().trim()
    }
};

QuizSchema.statics.joiValidationForQuizCreate = async (quizObject) => {
    const requiredSchema = Joi.object(validationSchema).fork(['title', 'description', 'createdBy.userId', 'createdBy.fullName', 'createdBy.email', 'updatedBy.userId', 'updatedBy.email', 'updatedBy.email'], item => item.required());
    return await requiredSchema.validateAsync(quizObject);
};

module.exports = mongoose.model('quiz', QuizSchema);

I want to access these Question fields using the Fork method as in the joiValidationForQuizCreate method. Is this possible or is there a better method available? I don't want to write schematics over and over on a case-by-case basis.



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source