Mongoose 是一个非常流行的 MongoDB ODM(对象文档映射)工具,它能够帮助我们更方便地在 Node.js 程序中使用 MongoDB 数据库。钩子函数是 Mongoose 中一个非常强大的特性,能够让我们在保存、更新等数据操作前后执行一些代码,实现比较复杂的功能。本文将从钩子函数的基本概念开始,详细介绍 Mongoose 中的钩子函数,并给出一些实际使用场景及示例代码,帮助读者更好地理解和使用这个功能。
什么是钩子函数?
在 Mongoose 中,钩子函数(hook)就是在进行数据库操作(如文档保存、删除、查询等)前后执行的一段程序。例如在保存一个文档前,我们可以执行一些字段校验、默认填充等操作;在查询后,我们可以对查询结果进行一定的处理和过滤。
Mongoose 钩子函数分为两类,分别是 Pre(前置)钩子和 Post(后置)钩子。前置钩子可以在进行数据库操作前执行,后置钩子则可以在操作后执行。钩子函数需要定义在 Schema(模式)中的方法中,Mongoose 会自动调用它们。
如何使用钩子函数?
在 Mongoose 中,钩子函数的使用非常简单。我们可以通过 schema.pre
和 schema.post
方法来定义前置和后置钩子函数,以处理存储或读取 MongoDB 数据的各种场景。
Pre Hooks 使用示例
前置钩子可以有多个,执行顺序从前往后。最为常见的一类是 save
钩子函数。当使用 model.save
或实例化后的文档进行 save
操作时都会提前执行。可以在下面示例中看到,在保存文档之前,执行了一些操作,比如校验和默认字段值填充。
-- -------------------- ---- ------- ----- -------- - -------------------- ----- ------ - ---------------- ----- ---------- - --- -------- ----- ------ -------- ---- ------ ------- --- -- --- ---- -- ---- -------- ---- ------ ---------------------- -------------- - ---------------- ---- ------- -- ------------ - ----------------- -- ------------ ------ -------- ----------- -- ------------- - -- ----------- - ---------------- ---- -- --- -- -- -- ----------- -------- - --- - ------- --- ----- --------- - ---------------------- ------------ -- ------------- ----- ---- - --- ------------ --------------- -- - -- ----- - ------------------- ---- --------- ------------- - ---- - ----------------- ----- ---------------- - ---展开代码
上述代码执行时,首先我们的 save 钩子函数会被触发,对 name 和 age 进行了校验和默认值填充,之后才会调用 UserModel
的实例 save
方法。
除此之外,Mongoose 还提供了许多其他的钩子函数,包括:
validate
一个属性在执行validate
方法之前触发。通常情况下,可以用于校验特定的字段的输入是否符合要求(如格式、长度等)。remove
该钩子在 Model 实例调用 remove 方法时执行。可以在此进行相关操作,例如同步删除数据前的其他关联数据。update
该钩子在执行 update 方法之前执行。可以尝试做一些条件的更新操作,避免浪费 update 操作。updateOne
updateOne 钩子与 update 钩子类似,只是在调用updateOne
时触发。
更多钩子函数请参见 Mongoose 的官方文档。
Post Hooks 使用示例
和 Pre Hooks 不同,Post Hooks 只能有一个。我们可以通过 schema.post
方法来注册后置钩子函数。下方是一个示例:在 document 上 apply hook,扩展事件追踪的处理,并把结果存到 DB 中。
-- -------------------- ---- ------- ----- -------- - -------------------- ----- ------ - ---------------- ----- ----------- - --- -------- ------ ------- --------- ------- ------ ------- -------- -------- --------- ------ ---------------- ---- -------- --- ------------------------ ------------- - ----- --- - - ----- -------- ------- --------- ------ -------- -------- --- ------- -- ----------------- ----- -- - -- ----- - ------------------- ----- --------- ------------- - ---- - ------------------ ----- ---------------- - --- --- ----- ---------- - ----------------------- ------------- -- -------------- ----- ----- - --- ------------ ------ --------- ---------- --------- -------- --- ---------------- -- - -- ----- - ------------------- ----- --------- ------------- - ---- - ------------------ ----- ---------------- - ---展开代码
Async Hooks
从 5.10.0 版本开始,Mongoose 引入了异步钩子函数,可以使用 schema.pre('save', { query: true, document: false }, async function() {})
的方式来定义。当 query: true
时,该钩子函数会在执行查询前执行(比如 findOne
方式), 当document: true
时只有当保存 Mongo 操作的时候执行, 这个特性通常使用在异步场景下(比如异步远程验证、密码哈希),尤其是异步验证更是使用上的方便。如下例所示:
-- -------------------- ---- ------- ---------------------- - ------ ----- --------- ----- -- ----- ---------- - ----- ---- - ----- ---------------- ---- ----- -- ----------- -- ------------ - ----------------- -- ------------ ----- --- ----------- -- ------------ - ----- ---- - ----- -------------- ----- --------- --- -- ------ - ----------------- ------- ---------- ----- --- ----------- ------- ---------- - ---展开代码
异步钩子函数中可以使用 await
等待异步操作的返回结果,可以更方便地处理异步场景下的数据操作。
Conclusion
Mongoose 钩子函数简单易用,但是强大的功能让它非常有用。比如可以在存储、更新数据之前,校验数据、填充默认值、处理关联关系等操作,确保数据的完整性和安全性。钩子函数也能帮助开发者简化代码逻辑,并且可以通过钩子函数更好地实现复杂的业务逻辑。实际项目中可以根据业务需要来选择不同的钩子函数,从而更好地使用 Mongoose 中的特性。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/67b9a05c306f20b3a6814b36