我正在尝试创建一个具有唯一用户名的用户模型。这是它的代码:
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);
我还测试了唯一性是否有效:
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(); });
问题是,事实并非如此。每次运行代码时,都会创建一个新对象。我知道,可能还有其他方法可以确保唯一性,但是我想以此方式进行。done处理该findOne方法的结果后,是否应该不打电话?我next打错电话了吗?
done
findOne
next
要使用并行中间件(带有next和done参数),您需要true作为第二个参数传递。
true
除此之外,还有两种可能性:
您的self.invalidate呼叫应引用"username"而不是"user"。如果那不能解决问题,可以通过将Error对象传递给done要中止保存操作的方法来明确地使事情失败:
self.invalidate
"username"
"user"
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(); });