Mongoose核心概念——Schema

869 阅读3分钟

之前的文章以一个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 索引,可用的字段如下:

  1. index:布尔值。是否在这个属性上定义一个索引。
  2. unique:布尔值。是否在这个属性上定义一个唯一的索引。
  3. 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)

推荐阅读

  1. 在 macOS 上安装 MongoDB
  2. MongoDB 增删改查操作
  3. Mongoose 入门,从一个 demo 开始
  4. Mongoose核心概念——连接数据库