I'm trying to create a User model, that has an unique username. Here's the code for it:
var mongoose = require("mongoose"); var Schema = mongoose.Schema; var UserSchema = new Schema({ username: String, password: String, }); UserSchema.virtual("password_confirmation").get(function() { return this.pw_conf; }).set(function(value) { this.pw_conf = value; }); UserSchema.path("username").required(true); UserSchema.path("password").required(true); UserSchema.pre("save",function(next, done) { var self = this; mongoose.models["User"].findOne({username : self.username},function(err, user) { if(user) { self.invalidate("user","username must be unique"); } done(); }); next(); }); UserSchema.pre("save",function(next) { if(this.pw_conf !== this.password) { next(new Error("Must specify the password confirmation")); } else { next(); } }); module.exports = mongoose.model("User",UserSchema);
I was also testing to see if the uniqueness works:
var User = require("./users"), mongoose = require("mongoose"); var u = new User(); mongoose.connect('mongodb://localhost/my_database'); u.username = "me"; u.password = "password"; u.password_confirmation = "password"; u.save(function(err) { if(err) { console.log(err); } mongoose.disconnect(); });
Problem is, it doesn't. Each time I run the code, I get a new object created. I am aware that there are probably other ways of ensuring uniqueness, but I'd like to do it in this way. Shouldn't I be calling done
after I handle the result of the findOne
method? Am I calling next
wrong?
mongoose-unique-validator is a plugin which adds pre-save validation for unique fields within a Mongoose schema. This makes error handling much easier, since you will get a Mongoose validation error when you attempt to violate a unique constraint, rather than an E11000 error from MongoDB.
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.
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.
Validation is an important part of the mongoose schema. Along with built-in validators, mongoose also provides the option of creating custom validations.
http://mongoosejs.com/docs/api.html#schematype_SchemaType-unique is the way to go. It uses actual MongoDb indexes to make sure that your field is unique. No need for .pre
middleware.
Enjoy!
To use parallel middleware (with next
and done
parameters), you need to pass true
as the second parameter.
Beyond that, there are two possibilities:
Your self.invalidate
call should be referencing "username"
instead of "user"
. If that doesn't fix it, you can fail things explicitly by passing an Error object to done
if you want to abort the save operation:
UserSchema.pre("save", true, function(next, done) { var self = this; mongoose.models["User"].findOne({username: self.username}, function(err, user) { if(err) { done(err); } else if(user) { self.invalidate("username", "username must be unique"); done(new Error("username must be unique")); } else { done(); } }); 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