数据类型与字段验证
数据类型基础
Mongoose 提供了丰富的数据类型用于定义模型字段。最常用的基本类型包括:
- String:字符串类型
- Number:数字类型
- Date:日期类型
- Boolean:布尔类型
- Buffer:二进制数据类型
- ObjectId:MongoDB文档ID
- Array:数组类型
- Mixed:混合类型
const userSchema = new mongoose.Schema({
name: String,
age: Number,
isActive: Boolean,
createdAt: Date,
hobbies: Array,
profile: Object
});
字段验证机制
Mongoose 的验证器在保存文档前自动执行。内置验证器包括:
- required:必填验证
- min/max:数值范围验证
- enum:枚举值验证
- match:正则匹配验证
- validate:自定义验证函数
const productSchema = new mongoose.Schema({
name: {
type: String,
required: true,
minlength: 3,
maxlength: 50
},
price: {
type: Number,
min: 0,
max: 10000
},
category: {
type: String,
enum: ['electronics', 'clothing', 'food']
}
});
自定义验证器
通过 validate 属性可以定义更复杂的验证逻辑:
const userSchema = new mongoose.Schema({
email: {
type: String,
validate: {
validator: function(v) {
return /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/.test(v);
},
message: props => `${props.value} 不是有效的邮箱地址`
}
},
age: {
type: Number,
validate: {
validator: function(v) {
return v >= 18 && v <= 120;
},
message: '年龄必须在18到120岁之间'
}
}
});
异步验证
对于需要异步操作的验证,可以返回 Promise:
const usernameSchema = new mongoose.Schema({
username: {
type: String,
validate: {
validator: function(v) {
return new Promise((resolve, reject) => {
User.findOne({ username: v })
.then(user => resolve(!user))
.catch(err => reject(err));
});
},
message: '用户名已存在'
}
}
});
嵌套对象验证
嵌套对象也可以应用验证规则:
const addressSchema = new mongoose.Schema({
street: { type: String, required: true },
city: { type: String, required: true },
zipCode: {
type: String,
validate: {
validator: function(v) {
return /^\d{5}(-\d{4})?$/.test(v);
}
}
}
});
const customerSchema = new mongoose.Schema({
name: String,
address: addressSchema
});
数组验证
数组字段可以验证元素类型和数量:
const postSchema = new mongoose.Schema({
tags: {
type: [String],
validate: {
validator: function(v) {
return v.length > 0 && v.length <= 5;
},
message: '标签数量必须在1到5个之间'
}
},
comments: [{
text: String,
author: String,
createdAt: { type: Date, default: Date.now }
}]
});
错误处理
验证失败时会抛出 ValidationError,可以捕获并处理:
const newUser = new User({ email: 'invalid-email' });
newUser.save()
.then(doc => console.log(doc))
.catch(err => {
if (err instanceof mongoose.Error.ValidationError) {
console.error('验证错误:', err.errors);
} else {
console.error('其他错误:', err);
}
});
自定义错误消息
可以为每种验证类型指定自定义错误消息:
const bookSchema = new mongoose.Schema({
title: {
type: String,
required: [true, '书名不能为空'],
minlength: [3, '书名至少3个字符'],
maxlength: [100, '书名最多100个字符']
},
isbn: {
type: String,
match: [/^\d{3}-\d{10}$/, 'ISBN格式应为XXX-XXXXXXXXXX']
}
});
条件验证
某些字段的验证可能需要依赖其他字段的值:
const orderSchema = new mongoose.Schema({
paymentMethod: {
type: String,
enum: ['credit', 'paypal', 'bank']
},
creditCardNumber: {
type: String,
validate: {
validator: function(v) {
return this.paymentMethod !== 'credit' ||
/^\d{16}$/.test(v);
},
message: '信用卡支付需要16位卡号'
}
}
});
验证中间件
使用 pre 钩子可以在保存前执行额外验证:
userSchema.pre('save', function(next) {
if (this.isModified('password') && this.password.length < 8) {
throw new Error('密码至少需要8个字符');
}
next();
});
禁用验证
在某些情况下可能需要跳过验证:
// 跳过所有验证
doc.save({ validateBeforeSave: false });
// 跳过特定路径验证
doc.save({ validateModifiedOnly: true });
自定义类型
可以创建自定义的 SchemaType 扩展:
class TruncateString extends mongoose.SchemaType {
constructor(key, options) {
super(key, options, 'TruncateString');
this.maxLength = options.maxLength || 100;
}
cast(val) {
let _val = String(val);
if (_val.length > this.maxLength) {
_val = _val.substring(0, this.maxLength);
}
return _val;
}
}
mongoose.Schema.Types.TruncateString = TruncateString;
const schema = new mongoose.Schema({
excerpt: { type: TruncateString, maxLength: 50 }
});
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:Schema的定义与结构
下一篇:自定义验证器与错误处理