mongoose custom validation using 2 fields

I want to use mongoose custom validation to validate if endDate is greater than startDate. How can I access startDate value? When using this.startDate, it doesn't work; I get undefined.

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 is a function that compares two dates.


Solution 1:

You can do that using Mongoose 'validate' middleware so that you have access to all fields:

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

Note that you must wrap your validation error message in a JavaScript Error object when calling next to report a validation failure. 

Solution 2:

An an alternative to the accepted answer for the original question is:

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

Solution 3:

I wanted to expand upon the solid answer from @JohnnyHK (thank you) by tapping into this.invalidate:

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

  next();
});

This keeps all of the validation errors inside of a mongoose.Error.ValidationError error. Helps to keep error handlers standardized. Hope this helps.

Solution 4:

You could try nesting your date stamps in a parent object and then validate the parent. For example something like:

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