Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoose unique validation error type

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?

like image 794
Olivier Avatar asked Nov 27 '12 09:11

Olivier


People also ask

How do you make a mongoose unique?

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.

What is validateBeforeSave?

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.)

Is Mongoose validation customizable?

Validation is an important part of the mongoose schema. Along with built-in validators, mongoose also provides the option of creating custom validations.

What is validation in mongoose?

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.


2 Answers

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 .

like image 137
Mushex Antaranian Avatar answered Sep 22 '22 00:09

Mushex Antaranian


I had some issues with the approved answer. Namely:

  1. this.model('User') didn't work for me.
  2. the callback 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.

like image 37
Sritam Avatar answered Sep 20 '22 00:09

Sritam