乐闻世界logo
搜索文章和话题

What are the types of data validation in Mongoose and how to implement custom validation?

2月22日 20:12

Mongoose provides powerful data validation features that allow validating data integrity and correctness before saving to the database. Validation can be defined at the Schema level or with custom validators.

Built-in Validators

1. Required Validation

javascript
const userSchema = new Schema({ name: { type: String, required: [true, 'Name is required'] }, email: { type: String, required: true } });

2. Type Validation

javascript
const userSchema = new Schema({ age: Number, isActive: Boolean, birthDate: Date });

3. Enum Validation

javascript
const userSchema = new Schema({ status: { type: String, enum: ['active', 'inactive', 'pending'], enum: { values: ['active', 'inactive', 'pending'], message: '{VALUE} is not a valid status' } } });

4. Range Validation (min, max)

javascript
const userSchema = new Schema({ age: { type: Number, min: [0, 'Age must be at least 0'], max: [120, 'Age cannot exceed 120'] }, score: { type: Number, min: 0, max: 100 } });

5. Length Validation (minlength, maxlength)

javascript
const userSchema = new Schema({ username: { type: String, minlength: [3, 'Username must be at least 3 characters'], maxlength: [20, 'Username cannot exceed 20 characters'] } });

6. Regex Validation (match)

javascript
const userSchema = new Schema({ email: { type: String, match: [/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/, 'Please fill a valid email address'] }, phone: { type: String, match: /^[0-9]{10}$/, message: 'Phone number must be 10 digits' } });

7. Unique Validation

javascript
const userSchema = new Schema({ email: { type: String, unique: true, index: true } });

8. Default Values

javascript
const userSchema = new Schema({ status: { type: String, default: 'active' }, createdAt: { type: Date, default: Date.now } });

Custom Validators

Single Field Validator

javascript
const userSchema = new Schema({ password: { type: String, validate: { validator: function(v) { return v.length >= 8; }, message: 'Password must be at least 8 characters long' } } });

Async Validator

javascript
const userSchema = new Schema({ email: { type: String, validate: { validator: async function(v) { const user = await this.constructor.findOne({ email: v }); return !user || user._id.toString() === this._id.toString(); }, message: 'Email already exists' } } });

Multi-field Validator

javascript
const userSchema = new Schema({ password: String, confirmPassword: String }); userSchema.path('confirmPassword').validate(function(v) { return v === this.password; }, 'Passwords do not match');

Validation Timing

Validation is automatically triggered at:

  • save() - When saving document
  • validate() - When explicitly calling validation
  • validateSync() - When synchronously validating
javascript
const user = new User({ name: '', age: -5 }); try { await user.save(); } catch (err) { console.log(err.errors.name.message); // "Name is required" console.log(err.errors.age.message); // "Age must be at least 0" }

Skipping Validation

In some cases, validation can be skipped:

javascript
// Skip validation when saving await user.save({ validateBeforeSave: false }); // Skip validation when updating await User.findByIdAndUpdate(id, { age: 25 }, { runValidators: false });

Validation Error Handling

javascript
userSchema.pre('validate', function(next) { if (this.password !== this.confirmPassword) { this.invalidate('confirmPassword', 'Passwords do not match'); } next(); }); // Catch validation errors try { await user.save(); } catch (err) { if (err.name === 'ValidationError') { Object.keys(err.errors).forEach(field => { console.log(`${field}: ${err.errors[field].message}`); }); } }

Best Practices

  1. Define validation rules at Schema level
  2. Provide clear error messages
  3. Use async validators to check uniqueness
  4. Validate on both frontend and backend
  5. Consider performance impact, avoid overly complex validation
  6. Use custom validators for business logic
  7. Log validation failures
标签:Mongoose