Mongoose 是 Node.js 环境下一个非常流行的 MongoDB 驱动程序,它提供了许多方便的特性来简化 MongoDB 数据库操作。其中生命周期钩子函数就是 Mongoose 中提供的一种非常有用的特性,它可以让我们在文档的保存、更新、删除和查询等过程中执行一些额外的操作,比如验证数据、处理敏感信息等。本文将详细介绍 Mongoose 中如何使用生命周期钩子函数,包括其 API、参数、执行顺序和常用场景等。
生命周期钩子函数 API
Mongoose 中定义了 4 个生命周期钩子函数,分别对应了文档对象的保存、更新、删除和查询操作,它们的名称和触发时机如下:
pre('save', callback)
: 在文档保存之前触发。pre('update', callback)
: 在文档更新之前触发。pre('findOneAndUpdate', callback)
: 在文档查询并更新之前触发。pre('remove', callback)
: 在文档删除之前触发。
在触发生命周期钩子函数时,Mongoose 会将钩子函数中传递的回调函数作为 next
参数传递进去,我们可以在回调函数中执行自定义的操作,然后调用 next
函数继续执行后续的操作。
生命周期钩子函数参数
生命周期钩子函数的回调函数中有两个参数:next
和 done
。
next
: 代表下一步执行的函数,如果在回调函数中不调用next
函数,则后续的操作将无法执行。在保存和更新操作中,Mongoose 默认会调用next
函数,但在查询操作中,需要手动调用next
函数才能继续执行查询操作。done
: 用于指示回调函数已经执行完毕,可以在回调函数中直接返回。
生命周期钩子函数执行顺序
在 Mongoose 中,生命周期钩子函数的执行顺序是按照它们定义的顺序依次执行的。例如,在文档保存操作上,如果先定义了 pre('save', [callback1])
,再定义了 pre('save', [callback2])
,那么 callback1
将先于 callback2
执行。注意,如果某个钩子函数中没有调用 next
函数,则后续的钩子函数将无法执行。
常用场景
下面列举了几种常见的使用场景,以便大家更好地理解生命周期钩子函数的具体应用。
数据验证
在保存或更新文档之前,我们可以使用生命周期钩子函数来验证文档的数据是否符合规范。例如,我们可以通过 pre('save', callback)
钩子函数来验证文档中必填的字段是否存在,并给出相应的错误提示,避免无效数据写入数据库。
举个例子,考虑一个 User 模型的定义,包含了 name 和 email 两个属性:
-- -------------------- ---- ------- ----- ---------- - --- ----------------- ----- - ----- ------- --------- ---- -- ------ - ----- ------- --------- ----- ---------- ----- ------- ----- --------- - ---------- ------- -- - ------ ------------------------- -- -------- -------- ----- -------- - - ---
我们可以在保存文档之前,使用 pre('save', callback)
钩子函数来进行数据验证:
-- -------------------- ---- ------- ---------------------- -------- ------ - ----- ---- - ----- -- ----------- -- ------------ - -- -------------------- ------ -------- -------------- ---- -- --------- - ------------------------------- -------- ----- - -- ----- - -- -------------------- ------ ---------- - -- ------------ ------- --- ---
这里的 validatePassword
函数可以用来对用户密码进行加密和验证,避免将用户密码明文保存在数据库中。
动态默认值
在 Mongoose 中,我们可以使用 default
属性为文档属性设置默认值,例如:
-- -------------------- ---- ------- ----- ---------- - --- ----------------- ----- - ----- ------- --------- ---- -- ----------- - ----- ----- -------- -------- - ---
但是有时候,我们需要将默认值设置为一个动态的值,例如当前时间、当前用户等。此时,我们可以使用生命周期钩子函数来实现:
userSchema.pre('save', function (next) { const user = this; if (!user.created_at) { user.created_at = new Date(); } next(); });
这里我们在保存文档之前,判断 created_at
是否存在,如果不存在,则设置为当前时间。
处理敏感信息
在保存或更新文档之前,我们可以使用生命周期钩子函数对敏感信息进行处理,例如对密码进行加密,对身份证号进行脱敏。这样可以保证敏感信息不被明文存储在数据库中。
-- -------------------- ---- ------- ---------------------- -------- ------ - ----- ---- - ----- -- ----------------------------- - ------------------ -------- ----- ----- - -- ----- - ------ ---------- - -------------------------- ----- -------- ----- ----- - -- ----- - ------ ---------- - -- -------------- ------------- - ----- ------- --- --- - ---- - ------- - ---
这里的 bcrypt
库是用来对密码进行加密的,它可以保证密码不被明文保存在数据库中。
示例代码
下面是使用 pre('save', callback)
钩子函数保存文档的示例代码,其中采用了数据验证和密码加密两个操作:
-- -------------------- ---- ------- ----- -------- - -------------------- ----- ------ - ------------------ -- -- ---- --- ----- ---------- - --- ----------------- ----- - ----- ------- --------- ---- -- ------ - ----- ------- --------- ----- ---------- ----- ------- ----- --------- - ---------- ------- -- - ------ ------------------------- -- -------- -------- ----- -------- - -- --------- - ----- ------- --------- ----- ---------- - - --- -- ------- -------- ---------------------- --------- - ------------------ -------- ----- ----- - -- ----- - ------ -------------- - --------------------- ----- ---------- --- - -- ----------- ---------------------- -------- ------ - ----- ---- - ----- -- ----------------------------- - -- -------- --------------------------- -------- ----- ----- - -- ----- - ------ ---------- - -- -------------- ------------- - ----- ------- --- - ---- - ------- - --- -- -- ---- -------- ----- ---- - ---------------------- ------------ ----- ---- - --- ------ ----- ------- ------ ------------------- --------- -------- --- ------------------ ----- - -- ----- - ------------------- - ---- - ------------------------- ----- -------- - ---
总结
生命周期钩子函数是 Mongoose 中非常有用的一个特性,可以在文档的保存、更新、删除和查询等操作中执行一些额外的操作,比如数据验证、动态默认值、处理敏感信息等。本文中我们介绍了生命周期钩子函数的 API、参数、执行顺序和常见应用场景,并给出了示例代码。掌握生命周期钩子函数的使用方法,可以大大简化复杂数据操作的流程,提高开发效率。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/64f30e7df6b2d6eab3c925ba