I'm using this schema with mongoose 3.0.3
from npm:
var schema = new Schema({ _id: Schema.ObjectId, email: {type: String, required: true, unique: true} });
If I try to save a email that is already in db, I expect to get a ValidationError
like if a required
field is omitted. However this is not the case, I get a MongoError: E11000 duplicate key error index
.
Which is not a validation error (happens even if I remove the unique:true).
Any idea why?
Mongoose doesn't handle unique on its own: { name: { type: String, unique: true } } is just a shorthand for creating a MongoDB unique index on name . For example, if MongoDB doesn't already have a unique index on name , the below code will not error despite the fact that unique is true.
validateBeforeSave , as the name implies, validates the mongoose object before persisting it to database. This is a schema level check, which, if not set to false, will validate every document. It includes both built-in (like a Number cannot contain string or a required field should exist etc.)
Validation is an important part of the mongoose schema. Along with built-in validators, mongoose also provides the option of creating custom validations.
Validation is defined in the SchemaType. Validation is middleware. Mongoose registers validation as a pre('save') hook on every schema by default. You can disable automatic validation before save by setting the validateBeforeSave option. You can manually run validation using doc.
I prefer putting it in path validation mechanisms, like
UserSchema.path('email').validate(function(value, done) { this.model('User').count({ email: value }, function(err, count) { if (err) { return done(err); } // If `count` is greater than zero, "invalidate" done(!count); }); }, 'Email already exists');
Then it'll just get wrapped into ValidationError
and will return as first argument when you call validate
or save
.
I had some issues with the approved answer. Namely:
this.model('User')
didn't work for me.done
wasn't working properly.I resolved those issues by:
UserSchema.path('email').validate(async (value) => { const emailCount = await mongoose.models.User.countDocuments({email: value }); return !emailCount; }, 'Email already exists');
I use async/await
which is a personal preference because it is much neater: https://javascript.info/async-await.
Let me know if I got something wrong.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With