使用2个字段进行猫鼬自定义验证

amg*_*han 33 mongoose mongodb node.js express

我想使用mongoose自定义验证来验证endDate是否大于startDate.如何访问startDate值?使用this.startDate时,它不起作用; 我得到了不确定.

var a = new Schema({
  startDate: Date,
  endDate: Date
});

var A = mongoose.model('A', a);

A.schema.path('endDate').validate(function (value) {
  return diff(this.startDate, value) >= 0;
}, 'End Date must be greater than Start Date');
Run Code Online (Sandbox Code Playgroud)

diff 是一个比较两个日期的函数.

Joh*_*yHK 81

您可以使用Mongoose 'validate' 中间件执行此操作,以便您可以访问所有字段:

ASchema.pre('validate', function(next) {
    if (this.startDate > this.endDate) {
        next(new Error('End Date must be greater than Start Date'));
    } else {
        next();
    }
});
Run Code Online (Sandbox Code Playgroud)

请注意,Error在调用next报告验证失败时,必须将验证错误消息包装在JavaScript 对象中. 

  • 这比接受的答案更简洁,谢谢@JohnnyHK (2认同)
  • 也许这是我的错,但我找到了另一种方法:我使用了`this.invalidate('myField','我的错误消息.',this.myField);`所以没关系,谢谢:) (2认同)

Jas*_*ust 29

对原始问题的接受答案的替代方案是:

var mongoose = require('mongoose'),
  Schema = mongoose.Schema;

// schema definition
var ASchema = new Schema({
  startDate: {
    type: Date,
    required: true
  },
  endDate: {
    type: Date,
    required: true,
    validate: [dateValidator, 'Start Date must be less than End Date']
  }
});

// function that validate the startDate and endDate
function dateValidator(value) {
  // `this` is the mongoose document
  return this.startDate <= value;
}
Run Code Online (Sandbox Code Playgroud)

  • 使用带有runValidators选项的.findOneAndUpdate时,此选项失败.这有错误的上下文所以.startDate将不可用:( (6认同)

Tom*_*kin 27

您可以尝试在父对象中嵌套日期戳,然后验证父对象.例如:

//create a simple object defining your dates
var dateStampSchema = {
  startDate: {type:Date},
  endDate: {type:Date}
};

//validation function
function checkDates(value) {
   return value.endDate < value.startDate; 
}

//now pass in the dateStampSchema object as the type for a schema field
var schema = new Schema({
   dateInfo: {type:dateStampSchema, validate:checkDates}
});
Run Code Online (Sandbox Code Playgroud)


小智 20

我想通过点击this.invalidate扩展@JohnnyHK(谢谢)的可靠答案:

Schema.pre('validate', function (next) {
  if (this.startDate > this.endDate) {
    this.invalidate('startDate', 'Start date must be less than end date.', this.startDate);
  }

  next();
});
Run Code Online (Sandbox Code Playgroud)

这会将所有验证错误保留在mongoose.Error.ValidationError错误中.有助于保持错误处理程序的标准化.希望这可以帮助.

  • Nix 以上,这个解决方案是完美的。应该是公认的。谢谢@kognizant !!! (2认同)

pru*_*ule 5

在验证器中使用'this'对我有用 - 在这种情况下,当检查电子邮件地址的唯一性时,我需要访问当前对象的id,以便我可以将其从计数中排除:

var userSchema = new mongoose.Schema({
  id: String,
  name: { type: String, required: true},
  email: {
    type: String,
    index: {
      unique: true, dropDups: true
    },
    validate: [
      { validator: validator.isEmail, msg: 'invalid email address'},
      { validator: isEmailUnique, msg: 'Email already exists'}
    ]},
  facebookId: String,
  googleId: String,
  admin: Boolean
});

function isEmailUnique(value, done) {
  if (value) {
    mongoose.models['users'].count({ _id: {'$ne': this._id }, email: value }, function (err, count) {
      if (err) {
        return done(err);
      }
      // If `count` is greater than zero, "invalidate"
      done(!count);
    });
  }
}
Run Code Online (Sandbox Code Playgroud)