之前的文章以一个demo介绍了Mongoose的入门知识,本文深入Mongoose介绍它的核心概念——Schema
Schema 是 Mongoose 的核心概念之一,它映射到 MongoDB 的集合上,定义该集合中每个 document 的形状。Schema 不仅定义 document 的属性,还定义 document 的实例方法、静态方法、中间件和复合索引。
配置 Schema 的属性
在 Mongoose 中,配置 Schema 的属性有一个专门的术语,即 SchemaType,它是一个对象,用于配置给定属性应该是什么类型,哪些值对该属性是合法的等。
type 字段
创建 Schema 时至少要指定属性的数据类型,此时 SchemaType 用到的字段是 type,type 的可能取值有 String、Number、Date、Buffer、Boolean、Mixed、ObjectId、Array、Decimal128、Map、Schema。如果只在 SchemaType 中使用 type 字段,那么等价于直接在属性后跟类型。示例代码如下:
new Schema({
name: String, // 等于 name: {type: String}
updated: Date,
age: Number,
binary: Buffer,
mixed: Schema.Types.Mixed,
_myId: Schema.Types.ObjectId,
map: Map,
isNew: Boolean,
BooleanArr: [Boolean],
address: {
city: String,
area: String,
},
subSchema: teacherSchema
})
定义索引
使用 SchemaType 定义 MongoDB 索引,可用的字段如下:
- index:布尔值。是否在这个属性上定义一个索引。
- unique:布尔值。是否在这个属性上定义一个唯一的索引。
- sparse:布尔值。是否在这个属性上定义一个稀疏索引。
代码如下:
new Schema({
name: {
type: String,
index: true,
unique: true
}
})
验证器
验证器是中间件,Mongoose 默认将验证器注册到 Schema 的 pre('save') hook 上,验证器是异步递归执行的,当在 document 上调用 save() 时,子 document 的验证器也会执行。除了使用自定义的验证器,还能使用内置的验证器,不同的数据类型支持的内置验证器不同,required 验证器对所有类型都支持。Number 类型还支持 min、max 和 enum 验证器;String 类型还支持 match、enum、minLength 和 maxLength 验证器。本文主要介绍自定义验证器。
自定义验证器通过给 validate.validator 传递一个函数来声明,代码如下:
new Schema({
age: {
type: Number,
validate: {
validator: (v: number) => {
return v % 4 === 0
},
message: 'age 不能被4整除'
}
},
email: {
type: String,
validate: {
validator: (v: string) => Promise.resolve(false),
message: 'email 验证失败'
}
}
})
自定义验证器可以是同步的,也能是异步的,如果验证器返回一个 promise 对象,那么 mongoose 将等待该 promise 变成 settled。如果 promise 的状态是 rejected 或者以 false 兑现,那么 Mongoose 将认为没有通过验证。
实例方法
实例方法指的是 document 的实例方法,document 有很多内置的实例方法,比如:save()、find()和 update(),访问mongoosejs.com/docs/api/do… 查看它的全部实例方法。本小节介绍如何给document添加自定义实例方法,代码如下:
const teacherSchema = new mongoose.Schema<ITeacher>({
name: String,
grade: Number,
salary: Number
});
teacherSchema.methods.findSimilarGrade = async function() {
// 这里的 this 是document
return await this.db.models['teacher'].find({grade: this.grade})
}
document 的实例方法在 Schema 的 methods 字段上,由于箭头函数没有自己的 this,所以不要用箭头函数定义实例方法。调用实例方法,代码如下:
const doc = new heyuConnection.models['teacher']({
name,
grade,
salary
})
const res = await doc.findSimilarGrade()
提示:在这里复用了Mongoose核心概念——连接数据库中建立多个连接的代码。
静态方法
静态方法指的是 Model 的静态方法,添加静态方法有两种方式,代码如下:
// 静态方法中的this是Model
teacherSchema.statics.findSimilarGrade = async function(grade: number) {
return await this.find({grade})
}
teacherSchema.static('findSimilarGrade', async function(grade: number) {
return await this.find({grade})
})
上述两种定义静态方法的方式是等效的,由于箭头函数没有自己的 this,所以不要使用箭头函数定义静态方法。调用静态方法的代码如下:
const res = await heyuConnection.models['teacher'].findSimilarGrade(grade)