在使用 MongoDB 作为数据库时,Mongoose 是 Node.js 中最广泛使用的 MongoDB 的 ODM 库,它提供了许多方便的 API 用于操作 MongoDB 数据库,如定义模型,查询,更新等。同时,Mongoose 还提供了一种叫做钩子(hook)的机制,用于在模型中的特定事件发生时执行一些操作,这个钩子机制十分强大,能够帮助我们更加灵活和方便地处理数据。本篇文章将会对 Mongoose 的钩子机制进行深入解析,并通过示例代码带领大家学习如何使用和优雅地实现数据操作。
钩子是什么?
Mongoose 中的钩子机制是指在模型中的文档操作触发特定事件时,执行特定的函数,以便更好地控制数据。钩子可以在插入,更新,删除文档时发生作用,而且它们可以在文档的不同生命周期中执行,比如在保存前,保存后,查询前,查询后等等。这个钩子机制是 Mongoose 的核心功能之一,可以大大简化代码逻辑,提高操作数据的效率和精度。
钩子机制的优点
Mongoose 钩子机制具有以下优点:
方便快速实现数据预处理:在存储或读取数据之前,先对数据进行处理,例如,计算某个值、进行数据格式转换,或检查数据是否符合要求等;
异步操作:Mongoose 钩子支持异步操作,例如在发送邮件或短信等场景中,我们可以在文档保存之后抓取到该事件以进行后续操作;
提升代码健壮性:在写钩子的同时,你可以很容易地处理边缘情况,并且防止出现一些不应该有的数据;
灵活运用数据:在保存数据之前或之后,你可以对数据进行修改或者一些操作,这可以避免在某些情况下使用难以维护的异步中间件。
钩子分类
Mongoose 钩子按照触发事件的时间可以被分为两类:
预钩子(pre-hooks):在触发操作前执行。例如,在保存文档之前,你可以对某些字段进行加密、格式化,以及做一些其他预处理的操作。
后钩子(post-hooks):在触发操作之后执行。例如,在保存文档之后,你可以在数据库中创建一些其他数据,发送某些电子邮件、短信消息等等。
Mongoose 可以为以下文档操作设置预钩子和后钩子:
- validate:保存之前验证数据;
- save:在保存之前或之后执行某些操作;
- remove:在删除一个文档之前或之后执行某些操作;
- init:在创建文档实例之后,在执行任何其他操作之前执行的操作;
- validate(字段名):验证特定字段之前或之后。
在进行下一步学习之前,需要先在 Node.js 项目中安装 mongoose
库。
--- ------- --------
示例
1、保存前对密码字段加密
首先,我们先看一个常见的使用场景,即在保存账号密码时,对密码进行加密的钩子例子,我们可以通过 Mongoose 提供的 pre-hooks 钩子在保存之前对密码进行加密。我们可以在保存文档之前进行处理,如下:
----- -------- - -------------------- ----- ------ - ------------------ ----- ---------- - --- ----- ---------- - --- ----------------- ----- ------- ------ ------- --------- ------ --- -- --- ------ ------ ---------------------- -------- ------ - ----- ---- - ----- -- ----------------------------- - -------------------------- ----- ----- -- - -------------------------- ----- ----- ----- -- - -- ----- - ------ ---------- - ------------- - ----- ------- --- --- - ---- - ------ ------- - ---
上述代码中,我们创建了一个用户模型,其中包括用户姓名,邮箱和密码,并创建了一个 pre-save
钩子,在保存一个文档之前进行处理if (user.isModified('password'))
,首先判断密码是否被修改,如果被修改了,将会执行以下两个步骤:
首先,我们调用
bcrypt
的genSalt()
函数并生成一个 salt(盐)来进行哈希,salt 的长度是 10 个字符;之后,我们调用
bcrypt.hash()
函数来生成哈希,并将结果保存到文档中。
2、在用户保存后发送电子邮件
现在来看一个更加复杂的例子,在用户保存之后,我们会发送一份确认电子邮件给该用户。在使用 Mongoose 后钩子的确切位置之前,您首先需要确信电子邮件服务提供商是否将其称为“异步”运行。
----------------------- -------- ----- - -- -------------- ----- ------ - -------------------- ----- ------ - --- --------- -------------------------------- ---------- - ----- -------- --- -- ---- ----------------- ------------ ----- -- ---------------- ---
上述代码定义了一个 post-save
钩子,发送一份确认电子邮件给该用户。在这篇文章中,模运行此代码的整个过程:此用户的帐户将记录在数据库中,确认电子邮件将发送,其中包括名称和电子邮件地址,具有使用后的电子邮件内容。您可以将此覆盖为您选择的电子邮件服务 API。
3、使用 query middleware,过滤被删除的用户
现在来看一下一个过滤已被删除用户的例子,并使用 query middleware 代替实例级别的 middleware。
我们将使用 Mongoose 的 pre-findOneAndDelete()
,该方法在文档删除之前运行,并且将运行之前findOneAndDelete()
中的查询语句。提前告诉你:这里的代码可能会导致数据丢失,实现必须谨慎审查。
---------------------------------- -------- ------ - ----- --- - ----- ------------------------ ------ --------- ---------------- -- - -- --------------- - ------ ------- - ---- - ------ -------- --------- ---- ----- ---- ----- ---------------- - -------------- -- - ------ ---------- --- ---
上述代码中,假设代码逻辑中删除操作只在传递使用者的电子邮件字段上完成,我们需要查找该用户,检查我们要删除的模型是否存在,如果模型不存在,则在 findOneAndDelete() 查询中的钩子结束执行,进入到下一个函数。
4、根据用户年龄动态更新其等级
最后我们来看一个计算用户等级的例子。通过使用pre-save
钩子,该等级将根据用户的年龄计算,并保存到users 模型中,等级取值在 1 至 10 之间,其中 1 表示是年龄最小的用户。
---------------------- -------- ------ - ----- ---- - ----- -- ------------------------ - ----- --- - --------- -- ---- -- --- - --------- - --- - ---- -- ---- - -- -- --- -- --- - --------- - -- - ---- -- ---- - -- -- --- -- --- - --------- - -- - ---- -- ---- - -- -- --- -- --- - --------- - -- - ---- -- ---- - -- -- --- -- --- - --------- - -- - ---- -- ---- - --- - --------- - -- - - ------ ------- ---
结论
在 Mongoose 中使用钩子机制能够对模型中的文档进行快速、方便的操作,自定义逻辑后,钩子机制的复杂性可以方便地起到帮助代码简化和精简操作的作用。在使用钩子机制时还需要注意数据的有效性和正常性,避免出现不必要的错误。钩子机制是一个广泛使用的技术,的确可以帮助您在控制模型数据时更加方便。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/67399834317fbffedf17930c