【问题标题】:Mongoose findOneAndUpdate and runValidators not working猫鼬 findOneAndUpdate 和 runValidators 不工作
【发布时间】: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 但结果相同。

【问题讨论】:

标签: node.js mongodb validation mongoose


【解决方案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】:

      在猫鼬中分两步做同样的事情。

      1. 使用findOne()方法查找结果。
      2. 使用Model.save()添加字段并保存文档。

      这将更新您的文档。

      【讨论】:

        猜你喜欢
        • 2013-02-13
        • 2020-11-13
        • 2019-11-10
        • 2021-09-25
        • 2017-10-05
        • 2015-10-26
        • 1970-01-01
        • 1970-01-01
        • 2016-06-20
        相关资源
        最近更新 更多