【发布时间】:2014-03-22 07:05:27
【问题描述】:
据我了解,mongoose 预保存钩子会在文档插入集合之前但在验证发生之后触发。因此,如果一次验证失败,则不会调用预保存挂钩。
在我的例子中,不管怎样,它们都会被调用:
下面的简单代码所做的是尝试创建一个模式,在该模式中,用户在注册时通过 _id 引用其他用户。添加了一个预保存挂钩以自动将新用户的 ID 推送到他们的推荐列表中。
所以用户 a 注册没有推荐 -> 好的
用户 b 向 a 注册作为推荐人 -> OK
用户 b2 使用与 b 相同的电子邮件注册(不正确,是唯一的)并引用 a -> 应该失败并且它不应该在 a.references 中推送 b2 的 ID
架构:
var userSchema = new Schema({
email: {type:String, unique:true, required:true},
isVerified: {type:Boolean, default:false},
referredBy: {type:Schema.ObjectId, ref:'User'},
referred: [{type:Schema.ObjectId, ref:'User'}],
});
userSchema.pre('save', function (next) {
if (!this.isNew) return next();
if (!this.referredBy) return next();
User.findById(this.referredBy, function (err, doc) {
if (err) return next(err);
if (!doc) return next(new DbError(['referredBy not found: %s', this.referredBy]));
doc.referred.push(this._id);
doc.save(next);
}.bind(this));
});
userSchema.path('referredBy').validate(function (value, respond) {
User.findById(value, function (err, user) {
if (err) throw err;
if (!user) return respond(false);
respond(true);
});
}, 'doesntExit');
var User = mongoose.model('User', userSchema);
测试代码:
var a = new User();
a.email = 'a';
a.save(function () {
var b = new User();
b.email = 'b';
b.referredBy = a._id;
b.save(function () {
var b2 = new User();
b2.email = 'b';
b2.referredBy = a._id;
b2.save(function (err, doc) {
console.log('error:', err); // duplicate error is thrown, which is OK
console.log(!!doc); // this is false, which is OK
User.findById(a._id, function (err, result) {
console.log('# of referrals: ', result.referred.length); // 2, which is BAD
});
});
});
});
其他所有检查,错误被抛出,失败发生,但所有预保存挂钩都被保存
知道如何解决这个问题,或者验证钩子后是否有真正的预保存?
【问题讨论】: