Mongoose findOneAndUpdate和runValidators无法正常工作

时间:2015-06-28 16:18:40

标签: node.js mongodb validation mongoose

我在试图获得“运行的人”时遇到了问题。工作的选择。我的用户架构有一个必须设置为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操作上运行。例如,无论数字的值如何,以下更新都将成功。

我用$ set替换了$ setOnInsert,但结果相同。

5 个答案:

答案 0 :(得分:6)

  当您尝试显式$取消设置密钥时,

必需的验证程序才会失败。

这对我来说毫无意义,但这是文档所说的。

答案 1 :(得分:4)

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

  1. 使用findOne()方法查找结果。
  2. 使用Model.save()添加字段并保存文档。
  3. 这将更新您的文档。

答案 2 :(得分:2)

使用此插件: mongoose-unique-validator

使用像findOneAndUpdate这样的方法时,您需要传递此配置对象:

{runValidators:true,context:' query' }

即。

User.findOneAndUpdate(
  { email: 'old-email@example.com' },
  { email: 'new-email@example.com' },
  { runValidators: true, context: 'query' },
  function(err) {
    // ...
}

答案 3 :(得分:1)

我创建了一个插件,用于在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);
    });

答案 4 :(得分:0)

我通过为findOneAndUpdate()添加一个预钩子来解决此问题:

ExampleSchema.pre('findOneAndUpdate', function (next) {
    this.options.runValidators = true
    next()
})

然后,当我使用findOneAndUpdate时,验证工作正常。