Validate object against Mongoose schema without saving as a new document
There is one way to do that through Custom validators
. When the validation failed, failed to save document into DB.
var peopleSchema = new mongoose.Schema({ name: String, age: Number });var People = mongoose.model('People', peopleSchema);peopleSchema.path('name').validate(function(n) { return !!n && n.length >= 3 && n.length < 25;}, 'Invalid Name');function savePeople() { var p = new People({ name: 'you', age: 3 }); p.save(function(err){ if (err) { console.log(err); } else console.log('save people successfully.'); });}
Or another way to do that through validate()
with same schema as you defined.
var p = new People({ name: 'you', age: 3});p.validate(function(err) { if (err) console.log(err); else console.log('pass validate');});
As explained here in the mongoose documents https://mongoosejs.com/docs/validation.html , you can use doc.validate(callback)
or doc.validateSync()
to check for validation.
The difference is that you do not have to use await
for validateSync()
as its name suggests. it returns an error if validation fails, otherwise, it returns undefined
.for example:
const model = new Model({somedata:somedata})const validatedModel = model.validateSync()if(!!validatedModel) throw validatedModel
I wrote the following function which doesn't need the model at all, you just pass an object and the Mongoose schema, no matter if it is as a document or a subdocument. Subdocuments are also checked recursively:
const validateObjectAgainstMongooseSchema = ({checkObject, mongooseSchema, currentPath = "object"} = {}) => { const errors = []; for (const key of Object.keys(checkObject)) { const checkObjectType = Array.isArray(checkObject[key]) ? "array" : typeof checkObject[key]; const mongooseType = mongooseSchema.path(key).instance.toLowerCase(); const valid = mongooseType === checkObjectType; if (checkObjectType === "object") { errors.push( ...validateObjectAgainstMongooseSchema({ checkObject: checkObject[key], mongooseSchema: mongooseSchema.path(key).schema, currentPath: `${currentPath}.${key}` }) ); } else if (!valid) { errors.push(`${currentPath}.${key} should be of type ${mongooseType} but got ${checkObjectType}`); } } return errors;};
when using the following schema:
const schema = new mongoose.Schema({ stringType: { type: String }, numberType: { type: Number }, dateType: { type: Date }, boolType: { type: Boolean }, arrayType: { type: Array }, schemaType: { type: new mongoose.Schema({ embeddedDate: { type: Date }, embeddedBool: { type: Boolean } }) } });
the following yields an empty array
const errors = schemaUtils.helpers.validateObjectAgainstMongooseSchema({ checkObject: { stringType: "test", numberType: 2, dateType: new Date("2020-01-01"), boolType: true, arrayType: ["test", "it"], schemaType: {embeddedDate: new Date("2020-01-02"), embeddedBool: true} }, mongooseSchema: schema });
and this
const errors = schemaUtils.helpers.validateObjectAgainstMongooseSchema({ checkObject: { stringType: 1, numberType: "1", dateType: 1, boolType: 1, arrayType: 1, schemaType: {embeddedDate: 1, embeddedBool: 1} }, mongooseSchema: schema });
yields:
[ 'object.stringType should be of type string but got number', 'object.numberType should be of type number but got string', 'object.dateType should be of type date but got number', 'object.boolType should be of type boolean but got number', 'object.arrayType should be of type array but got number', 'object.schemaType.embeddedDate should be of type date but got number', 'object.schemaType.embeddedBool should be of type boolean but got number' ]