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

Posted

技术标签:

【中文标题】使用 2 个字段的猫鼬自定义验证【英文标题】:mongoose custom validation using 2 fields 【发布时间】:2014-07-08 17:48:18 【问题描述】:

我想使用 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');

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

【问题讨论】:

【参考方案1】:

您可以使用 Mongoose 'validate' middleware 做到这一点,这样您就可以访问所有字段:

ASchema.pre('validate', function(next) 
    if (this.startDate > this.endDate) 
        next(new Error('End Date must be greater than Start Date'));
     else 
        next();
    
);

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

【讨论】:

我的控制器中有 nodejs exports.create = function (req, res, next) var a = new A(req.body); // 我在这里添加了你的代码,但它不起作用 newEvent.save(function(err) if (err) return res.json(400, err); return res.json(message:'success' ); ); @JohnnyHK:我应该在哪里添加您的代码示例谢谢 这比公认的答案更干净,谢谢@JohnnyHK 我试过了但是错误没有返回到entity.save()回调。 @AdrienG 如果您仍需要帮助,请继续发布一个包含完整详细信息的新问题。 也许这是我的错,但我找到了另一种方法:我改用 this.invalidate('myField', 'my error message.', this.myField); 所以没关系,谢谢 :)【参考方案2】:

原始问题已接受答案的另一种选择是:

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;

【讨论】:

太棒了!如果您需要两个字段之一,您可以在必填字段上创建验证,但请通过 this 检查您需要的内容。 此选项在使用带有 runValidators 选项的 .findOneAndUpdate 时失败。这有错误的上下文,所以 .startDate 将不可用:(【参考方案3】:

我想通过点击 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();
);

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

【讨论】:

正是我需要的!现在我只需要弄清楚为什么猫鼬在保存之前没有点击验证钩子...... 无视上述,这个解决方案是完美的。应该是被接受的。谢谢@kognizant !!!【参考方案4】:

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

//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
);

【讨论】:

【参考方案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);
    );
  

【讨论】:

【参考方案6】:

这是我使用的解决方案(感谢@shakinfree 的提示):

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

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

// function that validate the startDate and endDate
function dateValidator (value) 
    return value.startDate <= value.endDate;


module.exports = mongoose.model('A', ASchema);

【讨论】:

谨慎使用这种方法,因为 4.01 中存在错误 github.com/Automattic/mongoose/issues/2814

以上是关于使用 2 个字段的猫鼬自定义验证的主要内容,如果未能解决你的问题,请参考以下文章

使用带有打字稿的猫鼬创建自定义验证时出错

使用带有打字稿的猫鼬创建自定义验证时出错

带有嵌套可选对象和必填字段的猫鼬模式

mongoose 5.7.0 中的自定义验证

如果文件未导出,如何使用在单独文件中定义的猫鼬模型?

使用没有数组的嵌套文档为我的 JSON 定义有效的猫鼬模式?