Mongoose 是 Node.js 中使用最为广泛的 MongoDB 官方 ORM 库之一,它强大的数据建模能力和丰富的功能,使其成为了前端开发人员在使用 MongoDB 的过程中必不可少的工具。在使用 Mongoose 时,我们有时需要在数据存储和查询的过程中加入一些自定义的逻辑,并在其中进行一些操作,这时候,就需要使用到生命周期钩子(Lifecycle Hooks)来实现这种行为。
生命周期钩子是什么?
生命周期钩子是指在进行数据库操作的某些特定时间节点中所触发的函数。Mongoose 模型中的生命周期钩子通常会与 CRUD 操作相关,包括初始化、保存、更新、删除等等。这些钩子函数可以便捷地为你的模型添加特定行为,例如验证、转化属性类型、插入默认值等。
如何使用生命周期钩子
创建模型
我们首先要创建一个模型,以供后续的操作。在 Mongoose 中,模型是用来描述数据结构的一种抽象方式,它与具体的数据集合是相对应的。因此,我们要先创建一个数据集合,然后在该数据集合上定义模型,以供后续的操作。
-- -------------------- ---- ------- ----- -------- - -------------------- -- ---- --------------------------------------------------- - ---------------- ----- ------------------- ----- --- -- ---- ----- ---------- - --- ----------------- ----- ------- ------ ------- --------- ------- ----------- ----- ----------- ----- --- ----- ---- - ---------------------- ------------
添加生命周期钩子
Mongoose 中提供了多种钩子,用来在保存、查询、更新、删除等操作进行前后添加自定义操作。在定义模型时,我们使用 schema.pre(type, handler)
和 schema.post(type, handler)
方法添加钩子。对于生命周期钩子来说,这些类型包括:
init
validate
save
和insertMany
remove
这些类型均为模型 API 中的方法,添加钩子时参数为方法名,例如:
userSchema.pre("save", async function (next) { this.updated_at = new Date(); next(); });
这段代码为 User
模型添加了一个 save
钩子函数,并将执行的逻辑设为在保存该模型时自动将更新时间设为当前时间。
可以看到,我们只需要在 User
模型的原型上调用 pre
方法,然后传入钩子所绑定的函数和钩子会在哪一个操作中触发。注意:pre
中的钩子函数中必须调用 next()
才能让后续操作继续执行。
Mongoose 钩子函数使用了 this
关键字,因此我们可以在钩子函数中使用 this
来访问模型实例及其属性。例如:
userSchema.pre("save", async function (next) { const hash = await bcrypt.hash(this.password, 10); this.password = hash; next(); });
这段代码为 User
模型添加了一个 save
钩子函数,并将执行的逻辑设为在保存该模型之前,先对其密码进行加密处理,再保存。该钩子函数代码可以实现在存储用户数据时,将输入明文密码转化为加密密码。
状态机
Mongoose 钩子函数还可能有一些其他的功能,比如通过添加一个名为 $where
的状态变量,将钩子函数转换成状态机。状态机的作用是,将特定状态下的钩子函数的行为与检查条件关联起来。例如:
-- -------------------- ---- ------- ---------------------- ----- -------- ------ - -- ------------ - --------------- - --- ------- --------------- - --- ------- - ---- - --------------- - --- ------- - ------- ---
这是 User
模型的另一个 save
钩子函数。它使用 $where
状态变量将模型分为了 “新建” 和 “已存在” 两种状态,依据当前模型的状态,分别执行不同的逻辑。特别地,由于仅会在模型创建时初始化记录的 created_at
属性,因此钩子不会在模型更新时再次执行该逻辑。
查询钩子
查询钩子可以用于 Model.find()
、Model.findOne()
、Model.updateOne()
等的查询操作中,通过绑定 query
的钩子可以在执行查询操作前后添加自定义的操作。例如:
userSchema.pre("findOne", async function (next) { console.log(`find user by email address: ${this._conditions.email}`); next(); });
该代码为 User
模型的 findOne
钩子,该钩子会在执行查询操作前输出查询条件。根据查询条件中的名称,开发者可以知道是否有某些参数被误传或是被注入了恶意代码。
总结
生命周期钩子是 Mongoose 中非常有用的功能,可以帮助我们在存储、检索、更新或删除文档时执行一些自定义操作。在本文中,我们学习了如何使用 Mongoose 钩子函数,在储存操作和查询操作中添加钩子和状态机,来进行自定义操作。生命周期钩子的思想可以在不同场景下使用,并且可以灵活应用于不同的逻辑需求中。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/6502c21395b1f8cacdffb200