猫鼬 findOneAndUpdate 和 runValidators 不工作
Posted
技术标签:
【中文标题】猫鼬 findOneAndUpdate 和 runValidators 不工作【英文标题】:Mongoose findOneAndUpdate and runValidators not working 【发布时间】:2015-09-15 02:35:26 【问题描述】:我在尝试使“runValidators”选项工作时遇到问题。我的用户模式有一个需要设置为 true 的电子邮件字段,但每次将新用户添加到数据库(使用“upsert”选项)并且电子邮件字段为空时它不会抱怨:
var userSchema = new mongoose.Schema(
facebookId: type: Number, required: true,
activated: type: Boolean, required: true, default: false,
email: type: String, required: true
);
findOneAndUpdate
代码:
model.user.user.findOneAndUpdate(
facebookId: request.params.facebookId,
$setOnInsert:
facebookId: request.params.facebookId,
email: request.payload.email,
,
upsert: true,
new: true,
runValidators: true,
setDefaultsOnInsert: true
, function (err, user)
if (err)
console.log(err);
return reply(boom.badRequest(authError));
return reply(user);
);
我不知道我做错了什么,我只是按照文档:http://mongoosejs.com/docs/validation.html
在文档中是这样说的:
请注意,在 mongoose 4.x 中,更新验证器仅在 $set 和 $unset 操作上运行。例如,无论 number 的值如何,下面的更新都会成功。
我将 $setOnInsert 替换为 $set 但结果相同。
【问题讨论】:
github.com/Automattic/mongoose/issues/3124 【参考方案1】:如果您想使用 findOneAndUpdate 进行验证,您无法获取当前文档,但您可以获得此关键字的内容,并且在此关键字的内容中具有“op”属性,因此解决方案如下:
注意:是否使用上下文无关紧要。另外,不要忘记在 findOneAndUpdate 正文中发送包含“price”和“priceDiscount”的数据。
validate:
validator: function (value)
if (this.op === 'findOneAndUpdate')
console.log(this.getUpdate().$set.priceDiscount);
console.log(this.getUpdate().$set.price);
return (
this.getUpdate().$set.priceDiscount < this.getUpdate().$set.price
);
return value < this.price;
,
message: 'Discount price (VALUE) should be below regular price',
【讨论】:
【参考方案2】:我通过为 findOneAndUpdate() 添加一个 pre hook 解决了这个问题:
ExampleSchema.pre('findOneAndUpdate', function (next)
this.options.runValidators = true
next()
)
然后,当我使用 findOneAndUpdate 时,验证正在工作。
【讨论】:
【参考方案3】:使用这个插件: mongoose-unique-validator
当使用像findOneAndUpdate
这样的方法时,你需要传递这个配置对象:
runValidators: true, context: '查询'
即。
User.findOneAndUpdate(
email: 'old-email@example.com' ,
email: 'new-email@example.com' ,
runValidators: true, context: 'query' ,
function(err)
// ...
【讨论】:
谢谢,它适用于使用验证的嵌套字段【参考方案4】:仅当您尝试显式 $unset 密钥时,必需的验证器才会失败。
这对我来说毫无意义,但这是文档所说的。
【讨论】:
当我使用 $unset, key 然后它要求我进行验证。但是,我仍然没有更新收藏。【参考方案5】:在 mongoose 中执行更新操作之前,我创建了一个插件来验证所需的模型属性。
插件代码在这里
var mongoose = require('mongoose');
var _ = require('lodash');
var s = require('underscore.string');
function validateExtra(schema, options)
schema.methods.validateRequired = function()
var deferred = Promise.defer();
var self = this;
try
_.forEach(this.schema.paths, function (val, key)
if (val.isRequired && _.isUndefined(self[key]))
throw new Error(s.humanize(key) + ' is not set and is required');
);
deferred.resolve();
catch (err)
deferred.reject(err);
return deferred.promise;
module.exports = validateExtra;
必须作为模型中的方法显式调用,因此我建议在更新调用之前将其链接为 .then
链。
此处使用的插件
fuelOrderModel(postVars.fuelOrder).validateRequired()
.then(function()
return fuelOrderModel.findOneAndUpdate(_id: postVars.fuelOrder.fuelOrderId,
postVars.fuelOrder, runValidators: true, upsert: true,
setDefaultsOnInsert: true, new: true)
.then(function(doc)
res.json(fuelOrderId: postVars.fuelOrder.fuelOrderId);
);
, function(err)
global.saveError(err, 'server', req.user);
res.status(500).json(err);
);
【讨论】:
上述解决方案检查更新和插入新的。但是validatedRequired 应该只检查创建案例而不是更新案例,因为更新案例不需要拥有所有必需的密钥。 @AlanLee 当然,所以删除upsert: true
然后它就不会插入了。为解决问题的有效解决方案投票怎么样?【参考方案6】:
在猫鼬中分两步做同样的事情。
-
使用
findOne()
方法查找结果。
使用Model.save()
添加字段并保存文档。
这将更新您的文档。
【讨论】:
以上是关于猫鼬 findOneAndUpdate 和 runValidators 不工作的主要内容,如果未能解决你的问题,请参考以下文章
猫鼬 findOneAndUpdate 为 err 和 doc 返回 null(使用 Jest)
将 findOne 和 findOneAndUpdate 与 HTTP 请求一起使用(猫鼬)
猫鼬 findOneAndUpdate Upsert _id null?
当我使用Model.findOneAndUpdate时,不会调用用于保存和更新的猫鼬预钩子
猫鼬不是 $setting array.$.booleanValue 当我 findOneAndUpdate(paramOne: p, paramTwo, array.keyName: valueNa