更新

时间:2016-08-26 11:24:25

标签: javascript node.js mongodb validation mongoose

首先,this没有帮助。

让我们说,我们有一个用户模型:

const schema = new mongoose.Schema({
    active: { type: Boolean },
    avatar: { type: String }
});

const User = mongoose.model('User', schema);

当我们更新它(设置一个头像)时:

// This should pass validation
User.update({ _id: id }, { $set: { avatar: 'user1.png' } });

我们希望根据当前(或更改的)active属性值对其进行验证。

案例#1

  • activefalse
  • 我们不应该能够设置头像 - 不应该通过验证

案例#2

  • activetrue
  • 我们应该能够设置头像 - 应该通过验证

  1. 使用自定义验证程序
  2. const schema = new mongoose.Schema({
        active: { type: Boolean },
        avatar: { type: String, validate: [validateAvatar, 'User is not active'] }
    });
    
    function validateAvatar (value) {
        console.log(value); // user.avatar
        console.log(this.active); // undefined
    }
    

    因此,我们无法访问active字段,因此无效。

    1. 使用pre"验证"钩
    2. schema.pre('validate', function (next) {
          // this will never be called
      });
      

      此挂钩不适用于update方法。

      1. 使用pre"更新"钩
      2. schema.pre('update', function (next) {
            console.log(this.active); // undefined
        });
        

        这对我们无效,因为它无法访问模型字段。

        1. 使用帖子"更新"钩
        2. schema.post('update', function (next) {
              console.log(this.active); // false
          });
          

          这个有效,但在验证方面不是很好的选择,因为只有在模型已经保存时才会调用该函数。

          问题

          在使用model.update()方法时,有没有办法在保存之前根据几个字段(保存在DB和新的字段中)验证模型?

          总结:

          1. 初始用户对象
          2. { active: false, avatar: null }
            
            1. 更新
            2. User.update({ _id: id }, { $set: { avatar: 'user1.png' } });
              
              1. 验证应该有权访问
              2. { active: false, avatar: 'user1.png' }
                
                1. 如果验证失败,则不应将更改传递给DB

5 个答案:

答案 0 :(得分:3)

由于使用update()的限制,我决定以这种方式解决问题:

  • 使用自定义验证器(问题中提到的想法#1)
  • 请勿使用update()

所以而不是

User.update({ _id: id }, { $set: { avatar: 'user1.png' } });

我用

User.findOne({ _id: id })
    .then((user) => {
        user.avatar = 'user1.png';
        user.save();
    });

在这种情况下,自定义验证程序按预期工作。

P.S。我选择这个答案对我来说是正确的,但我会给予最相关答案的赏金。

答案 1 :(得分:1)

您可以使用unordered-containers中指定的上下文选项执行此操作。

  

上下文选项

     

上下文选项允许您在更新验证程序中设置此值   到底层查询。

<小时/> 因此,在您的代码中,您可以在路径上定义validator,如下所示:

function validateAvatar (value) {
    // When running update validators with the `context` option set to
    // 'query', `this` refers to the query object.
    return this.getUpdate().$set.active;
}

schema.path('avatar').validate(validateAvatar, 'User is not active');

在更新时,您需要输入两个选项runValidatorscontext。因此,您的更新查询将变为:

var opts = { runValidators: true, context: 'query' };
user.update({ _id: id }, { $set: { avatar: 'user1.png' }, opts });

答案 2 :(得分:1)

您是否尝试过激活默认值,以便在mongodb中不会定义。

const schema = new mongoose.Schema({
active: { type: Boolean, 'default': false },
avatar: { type: String,
          trim: true,
          'default': '',
          validate: [validateAvatar, 'User is not active']
}});

function validateAvatar (value) {
    console.log(value); // user.avatar
    console.log(this.active); // undefined
}

创建时,您是否以这种方式设置用户

  var User = mongoose.model('User');
  var user_1 = new User({ active: false, avatar: ''});
  user_1.save(function (err) {
            if (err) {
                return res.status(400).send({message: 'err'});
            }               
            res.json(user_1);                
        });

答案 3 :(得分:0)

你可以尝试使用pre&#34; save&#34;钩。我之前用过它,可以在&#34;这个&#34;中获得价值。

schema.pre('save', function (next) {
    console.log(this.active);
});

希望这也适合你!

答案 4 :(得分:0)

您必须使用asynchronous custom validator

const schema = new mongoose.Schema({
  active: { type: Boolean },
  avatar: {
    type     : String,
    validate : {
      validator : validateAvatar,
      message   : 'User is not active'
    }
  }
});

function validateAvatar(v, cb) {
  this.model.findOne({ _id : this.getQuery()._id }).then(user => {
    if (user && ! user.active) {
      return cb(false);
    } else {
      cb();
    }
  });
}

(并按照Naeem的回答中的建议,将runValidatorscontext选项传递给update()

但是,这需要对每次更新进行额外查询,这不是理想的。

作为替代方案,您也可以考虑使用类似的东西(如果无法更新非活动用户的约束比实际验证它更重要):

user.update({ _id : id, active : true }, { ... }, ...);