Following up from : 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} });
With this middleware to get a validationError from unique:true
schema.pre("save", function(next, done) { var self = this; model.findOne({email : this.email}, 'email', function(err, results) { if(err) { done(err); } else if(results) { console.warn('results', results); self.invalidate("email", "email must be unique"); done(new Error("email must be unique")); } else { done(); } }); next(); });
However, it does not work!
Users.create()
will still return a a MongoError: E11000 duplicate key error index
and the console.warn()
is only called after that.
The save action should not be called until all middleware done()
have been called according to the docs, and I should get back a validation error.
It looks like the done()
behavior is not working as expected,
Any idea why?
save() is a method on a Mongoose document. The save() method is asynchronous, so it returns a promise that you can await on.
The save() function triggers validate() hooks, because mongoose has a built-in pre('save') hook that calls validate() . This means that all pre('validate') and post('validate') hooks get called before any pre('save') hooks.
While save() returns a promise, functions like Mongoose's find() return a Mongoose Query . Mongoose queries are thenables. In other words, queries have a then() function that behaves similarly to the Promise then() function. So you can use queries with promise chaining and async/await.
Mongoose save with an existing document will not override the same object reference. Bookmark this question.
You're using a parallel middleware callback function (with both next
and done
), but you're not setting the parallel flag in the schema.pre
parameters so it's using the serial rules.
So either include the parallel flag in your call:
schema.pre("save", true, function(next, done) { ...
Or switch to a serial middleware callback style if that's all you need anyway:
schema.pre("save", function(next) { var self = this; model.findOne({email : this.email}, 'email', function(err, results) { if(err) { next(err); } else if(results) { console.warn('results', results); self.invalidate("email", "email must be unique"); next(new Error("email must be unique")); } else { next(); } }); });
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