Search code examples
node.jsmongoosemongoose-schema

why mongoose validator not validating field type?


I am trying to validate mongoose schema, but i could not able to understand one thing which is a validation of type. I am passing number type to a string field and expecting it to fail in validation but it passes. how that is happening, can anyone please explain the logic behind this?

sample.js

const mongoose = require('mongoose');

async function validateSample(sample) {
  try {
    await sample.validate();
    return true;
  } catch (error) {
    return false;
  }
}

async function execMethod(){
  var userSchema = new mongoose.Schema({
    phone: {
      type: String,
      minlength: 2,
      maxlength: 4,
      validate: {
        validator: function(v) {
          return /^\d+$/.test(v);
        },
        message: `not a valid phone number!`
      },
      required: [true, 'User phone number required']
    }
  });
  
  var User = mongoose.model('user', userSchema);
  var validUser = new User({phone: '1234'});
  var invalidUser = new User({phone: 1235});
  const result = await validateSample(validUser);
  const result1 = await validateSample(invalidUser);
  console.log(result);  // true
  console.log(result1)  // expected false as number type is assigned to phone. But returns true, why?
}

execMethod()



Solution

  • That's actually a feature of Mongoose validation.

    Before running validators, Mongoose attempts to coerce values to the correct type. This process is called casting the document. If casting fails for a given path, the error.errors object will contain a CastError object.

    Casting runs before validation, and validation does not run if casting fails.

    In this case, a number 1235 gets cast to a string '1235', which passed the validation just fine.

    Now, there's a FR open for providing Mongoose with ability to override cast logic (either disable it completely or customize), but it's Open, not implemented.

    Another way is altering casting type-wide (allowed since 5.4), like this:

    mongoose.Schema.Types.String.cast(false); // prevents all casts to string
    

    ... but it might be cumbersome, as the same rule's applied to all the objects.