我一直在尝试运行自定义验证程序来检查用户输入的名称是否已存在于数据库中。因为,mongoDb将大写和小写名称视为不同,我为它创建了自己的验证器。
function uniqueFieldInsensitive ( modelName, field ){
return function(val, cb){
if( val && val.length ){ // if string not empty/null
var query = mongoose.models[modelName]
.where( field, new RegExp('^'+val+'$', 'i') ); // lookup the collection for somthing that looks like this field
if( !this.isNew ){ // if update, make sure we are not colliding with itself
query = query.where('_id').ne(this._id)
}
query.count(function(err,n){
// false when validation fails
cb( n < 1 )
})
} else { // raise error of unique if empty // may be confusing, but is rightful
cb( false )
}
}
}
现在,问题是验证程序在将文档保存在数据库中时运行,但在更新时不运行。
由于我使用的是mongoose版本4.x,我还尝试在更新查询中使用{ runValidators: true }
。这不起作用,因为我的验证器中的'this'关键字在更新的情况下是'null',而在保存的情况下它指的是更新的doc。
如果我遗漏了某些内容,或者在更新查询中有任何其他方式可以运行自定义验证器,请您告诉我。
答案 0 :(得分:2)
最后我找到了解决这个问题的方法。 根据MongoDB文档,它说:
首先,更新验证器只检查$ set和$ unset操作。更新验证程序不会检查$ push或$ inc操作。 第二个也是最重要的区别在于,在文档验证器中,这指的是正在更新的文档。对于更新验证程序,没有基础文档,因此在自定义验证程序中这将为null。 请参阅:Validators for update()
所以,现在我们只在调查中调用save()而不是update()。由于save()调用所有自定义和内置验证器,因此我们的验证器也将被调用。我是这样实现的:
function(req, res, next) {
_.assign(req.libraryStep, req.body);
req.libraryStep.save().then(function(data){
res.json(data);
}).then(null, function (err) {
console.info(err);
var newErr = new errorHandler.error.ProcessingError(errorHandler.getErrorMessage(err));
next(newErr);
});
};
注意这里req.libraryStep
是我从数据库中查询的文档。我使用了lodash方法assign
,它接受更新的json并将其分配给现有的数据库文档。
我不认为这是理想的方式,但至于现在直到Mongoose没有提供支持自定义验证器,我们可以用它来解决我们的问题。
答案 1 :(得分:1)
这是一个相当陈旧的主题,但我想像那样更新那些遇到过它的人的答案。
虽然您对更新验证程序中this
为空的上下文(根据文档)是正确的,但您可以使用context
选项设置{{1}的上下文}。 See the docs
但是,还存在一个插件,用于检查您正在设置的字段的唯一性:mongoose-unique-validator。我用它来检查重复的电子邮件。这也有一个不区分大小写的选项,所以我会检查出来。它也可以使用带有this
选项的update
命令正确运行。