Blog

Mongoose Validation

June 4, 2014

Mongoose Validation

Mongoose Validation

사실 Database Layer 에서 Validation 을 하는건 좋은 방법은 아닌 것 같습니다. Front 단에서도 필요하고, Back 단에서도 필요하지만, Back 단에서는 가능하다면 Server Application 단에서 처리하는게 더 나아 보입니다. 저 처럼 무식하게 mongoose validation 을 검색하신 분이 아니라면, 삽질 시간을 줄여드리기 위해서 조용히 express-validator 를 추천해 드립니다.

1. mongoose.Schema.path.validate

User.path('email').validate(function(v, fn) {
  // Make sure the email address is not already registered
  var UserModel = mongoose.model('User');
  UserModel.find({'email': v.toLowerCase()}, function (err, emails) {
    fn(err || emails.length === 0);
  });
}, 'Email is already registered');
var toySchema = new Schema({
  color: String,
  name: String
});

var Toy = mongoose.model('Toy', toySchema);

Toy.schema.path('color').validate(function (value) {
  return /blue|green|white|red|orange|periwinkle/i.test(value);
}, 'Invalid color');

var toy = new Toy({ color: 'grease'});

toy.save(function (err) {
  // err is our ValidationError object
  // err.errors.color is a ValidatorError object

  console.log(err.errors.color.message) // prints 'Validator "Invalid color" failed for path color with value `grease`'
  console.log(String(err.errors.color)) // prints 'Validator "Invalid color" failed for path color with value `grease`'
  console.log(err.errors.color.type)  // prints "Invalid color"
  console.log(err.errors.color.path)  // prints "color"
  console.log(err.errors.color.value) // prints "grease"
  console.log(err.name) // prints "ValidationError"
  console.log(err.message) // prints "Validation failed"
});

2. Schema Validation

function validator (val) { return val == 'something'; }
var custom = [validator, 'validation failed']
new Schema({ name: { type: String, validate: custom }});
var genders = 'MALE FEMALE'.split(' ')

var UserSchema = mongoose.Schema({
    name: {type: String, required: true}, // 1. Required validation
    age: {type: Number, min: 16, max: 60}, // 2. Minimum and Maximum value validation
    gender: {type: String, enum: genders}, // 3. ENUM validation
    email: {type: String, match: /\S+@\S+\.\S+/} // 4. Match validation via regex
});

var User = mongoose.model('User', UserSchema);


new User({age: 25}).validate(function (error) {
    console.log("ERROR: ", error); // Error for Name Field because its marked as Required.
});
new User({name: "Amit Thakkar", age:15}).validate(function (error) {
    console.log("ERROR: ", error); // Error for Age Field, age is less than Minimum value.
});
new User({name: "Amit Thakkar", age:61}).validate(function (error) {
    console.log("ERROR: ", error); // Error for Age Field, age is more than Maximum value.
});
new User({name: "Amit Thakkar", age:25, gender:"male"}).validate(function (error) {
    console.log("ERROR: ", error); // Error for Gender Field, male does not match with ENUM.
});
new User({name: "Amit Thakkar", age:25, gender:"MALE", email:"amit.kumar@intelligrape"}).validate(function (error) {
    console.log("ERROR: ", error); // Error for Invalid Email id.
});
new User({name: "Amit Thakkar", age:25, gender:"MALE", email:"[email protected]"}).validate(function (error) {
    console.log("ERROR: ", error); // Error will be undefined
});

Schema.pre

schema.pre("save", function(next) {
    var self = this;

    model.findOne({email : this.email}, 'email', function(err, results) {
        if(err) {
            next(err);
        } else if(results) {
            console.warn('results', results);
            self.invalidate("email", "email must be unique");
            next(new Error("email must be unique"));
        } else {
            next();
        }
    });
});

참고로, pre 에서 function(next, done) 콜백을 사용할수도 있는데, 이건 parallel middleware callback 입니다. 자세한 내용은 여기 를 참고하세요

Tip: set

function toLower (v) {
  return v.toLowerCase();
}

var UserSchema = new Schema({
  email: { type: String, set: toLower } 
});

References

  1. http://nraj.tumblr.com/post/38706353543/handling-uniqueness-validation-in-mongo-mongoose
  2. http://mongoosejs.com/docs/validation.html
  3. http://stackoverflow.com/questions/11872556/what-am-i-doing-wrong-in-this-mongoose-unique-pre-save-validation
  4. http://stackoverflow.com/questions/13582862/mongoose-pre-save-async-middleware-not-working-as-expected
  5. http://www.intelligrape.com/blog/2014/02/19/validation-with-mongoose/
  6. http://stackoverflow.com/questions/11325372/mongoose-odm-change-variables-before-saving
Array