簡體   English   中英

在更新時對幾個字段進行Mongoose自定義驗證

[英]Mongoose custom validation of several fields on update

首先, 沒有幫助。

比方說,我們有一個用戶模型:

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. 使用自定義驗證器
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. 使用預“驗證”鈎子
schema.pre('validate', function (next) {
    // this will never be called
});

此掛鈎不適用於update方法。

  1. 使用pre“update”掛鈎
schema.pre('update', function (next) {
    console.log(this.active); // undefined
});

這對我們不起作用,因為它無法訪問模型字段。

  1. 使用post“update”hook
schema.post('update', function (next) {
    console.log(this.active); // false
});

這個可行,但在驗證方面不是很好的選擇,因為只有在模型已經保存時才調用該函數。

那么有沒有一種方法可以在保存之前基於幾個字段(保存在DB和新的字段中)驗證模型,同時使用model.update()方法?

作為總結:

  1. 初始用戶對象
{ active: false, avatar: null }
  1. 更新
User.update({ _id: id }, { $set: { avatar: 'user1.png' } });
  1. 驗證應該有權訪問
{ active: false, avatar: 'user1.png' }
  1. 如果驗證失敗,則不應將更改傳遞給DB

由於使用update()限制,我決定以這種方式解決問題:

  • 使用自定義驗證器(問題中提到的想法#1)
  • 不要使用update()

而不是

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

我用

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

在這種情況下,自定義驗證程序按預期工作。

PS我選擇這個答案對我來說是正確的,但我會給予最相關答案的賞金。

您可以使用mongoose文檔中指定的context選項執行此操作。

上下文選項

context選項允許您將更新驗證程序中的this值設置為基礎查詢。


因此,在您的代碼中,您可以在路徑上定義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 }); 

您是否嘗試激活默認值,以便在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);                
        });

您可以嘗試預先“保存”鈎子。 我之前使用過它,可以在“this”中獲得值。

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

希望這也和你合作!

您必須使用異步自定義驗證器

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();
    }
  });
}

(並將runValidatorscontext選項傳遞給update() ,如Naeem的答案所示)。

但是,這將需要對每個更新進行額外查詢,這並不理想。

作為替代方案,您還可以考慮使用類似的東西(如果無法更新非活動用戶的約束比實際驗證它更重要):

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM