猫鼬 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?

猫鼬 findOneAndUpdate 不更新

当我使用Model.findOneAndUpdate时,不会调用用于保存和更新的猫鼬预钩子

猫鼬不是 $setting array.$.booleanValue 当我 findOneAndUpdate(paramOne: p, paramTwo, array.keyName: valueNa