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

Mongoose 数据验证有哪些类型,如何实现自定义验证?

2月22日 20:12

Mongoose 提供了强大的数据验证功能,可以在保存数据到数据库之前验证数据的完整性和正确性。验证可以在 Schema 层面定义,也可以自定义验证器。

内置验证器

1. 必填验证(required)

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

2. 类型验证(type)

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

3. 枚举验证(enum)

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. 范围验证(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. 长度验证(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. 正则表达式验证(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)

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

8. 默认值(default)

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

自定义验证器

单字段验证器

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

异步验证器

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

多字段验证器

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

验证时机

验证在以下时机自动触发:

  • save() - 保存文档时
  • validate() - 显式调用验证时
  • validateSync() - 同步验证时
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" }

跳过验证

在某些情况下,可以跳过验证:

javascript
// 跳过验证保存 await user.save({ validateBeforeSave: false }); // 跳过验证更新 await User.findByIdAndUpdate(id, { age: 25 }, { runValidators: false });

验证错误处理

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

最佳实践

  1. 在 Schema 层面定义验证规则
  2. 提供清晰的错误消息
  3. 使用异步验证器检查唯一性
  4. 在前端和后端都进行验证
  5. 考虑性能影响,避免过于复杂的验证
  6. 使用自定义验证器处理业务逻辑
  7. 记录验证失败的情况
标签:Mongoose