Mongoose 如何进行数据的字段验证?

阅读时长 8 分钟读完

在 Node.js 中,Mongoose 是一个非常流行的 MongoDB 数据库对象建模工具。它提供了一种优雅的方式来定义和操作数据模式,使得我们可以更加轻松地进行查询、更新、删除等操作。不仅如此,Mongoose 还提供了强大的数据字段验证功能,以确保我们的数据在存储到数据库中之前是完整、可靠、有效的。在本文中,我们将深入学习 Mongoose 的数据字段验证机制,以及如何在实际项目中使用它。

1. 概述

在 Mongoose 中,数据字段验证由 Schema 和 Model 两个组件共同实现。Schema 是用来定义数据模型的结构和规则的,包括字段名称、类型、默认值、验证规则等;而 Model 则是用来创建数据的实例对象,同时会通过 Schema 来验证数据是否可用。我们可以通过 Schema 的 validate 方法或者钩子函数来自定义数据字段验证的规则,以保证数据的完整性和正确性。

2. 自定义验证规则

Mongoose 内置了很多常见的验证规则,例如必填字段、字符串长度、数字范围、日期格式等,可以直接在 Schema 中使用。但是,有时候我们需要定义一些更加复杂的验证规则,例如对数组里的每个元素进行验证、跟其他字段关联的验证等,这时候就需要自定义规则了。

2.1 使用 validate 方法

在 Mongoose 中,可以通过在字段定义中添加 validate 属性来自定义验证规则。validate 属性是一个数组,包含多个 Validator 函数。Validator 函数接收一个参数 value,表示待验证的字段值,返回一个布尔值或者抛出一个验证错误。

例如,我们要定义一个 user 模型,包含 name 字段和 age 字段,其中 name 为必填字段,且长度不能超过 20 个字符;age 为可选字段,但是如果提供了值,它必须大于等于 18 岁,才能保存到数据库中。此时,我们可以这样定义 Schema:

-- -------------------- ---- -------
----- ---------- - --- -----------------
  ----- -
    ----- -------
    --------- -----
    ---------- ---
    --------- -
      ---------- ------- -- --------- -----------------
      -------- -------- ---- -------
    -
  --
  ---- -
    ----- -------
    ---- ---- ---- --------
    --------- -
      ------- -- ------ -- ----- -- ---
      ---- ------
    -
  -
---

在上面的例子中,我们使用了 validate 方法来自定义了两个验证规则。对于 name 字段,我们使用了正则表达式来限制其只能包含字母和空格,如果不符合规则,则抛出 'Invalid name format' 错误。对于 age 字段,我们使用了较为简单的 validate 函数,对值进行大于等于 18 岁的判断,并抛出 'Too young' 错误。

使用 validate 方法有一个问题,就是当存在多个验证规则时,最后只会捕获一个错误,且顺序不固定。因此,更好的选择是使用 pre 和 post 钩子函数来自定义验证规则。

2.2 使用钩子函数

在 Mongoose 中,Schema 中的 save、validate 等方法执行前后,可以依次执行中间件函数,从而实现自定义验证逻辑。中间件函数有 pre 和 post 两种类型,前者是异步函数,可以在实例化或者保存数据之前进行验证或者数据加工;后者是同步函数,可以在成功保存或者失败添加等事件后进行数据处理。下面分别介绍两种钩子函数的用法。

2.2.1 使用 pre 钩子

pre 钩子是在前置钩子函数中执行的,可以在实例化或者保存数据之前进行验证或者数据加工操作。pre 钩子函数有以下六个参数:

  • this:代表当前实例对象(this 指针);
  • next:代表进入下一个 pre 中间件函数的函数,需要显式调用才能生效;如果抛出异常,则当前操作会被撤回;
  • done:代表当前操作结束的回调函数,通常用于执行异步操作;
  • error:代表 pre 中间件函数执行时抛出的错误,如果存在则不会执行当前及之后的中间件函数;
  • result:代表上一个中间件函数的返回值(前提是该函数返回 Promise);
  • params:代表传递给 pre 函数的参数数组,调用时是使用 apply/call 来传递的。

例如,我们要在保存 user 模型操作之前,对某些字段进行验证。可以通过 pre 中间件函数来实现:

-- -------------------- ---- -------
---------------------- -------- ------ -
  -- --------- - -- -- --------- -
    ------ -------- ---------- --------
  -
  -- ----------- --------------------- -
    ------ -------- -------------- ---- ---------
  -
  ------
--

在上述代码中,我们定义了一个 pre 中间件函数,监听了 save 事件。在函数中,我们首先对 age 字段进行了大于等于 18 岁的验证,如果不符合条件,则抛出一个错误。然后,我们对 name 字段进行了正则表达式验证,如果不符合条件,则同样抛出一个错误。最后,如果没有出现错误,则调用 next 函数进入下一个中间件函数,或者执行记录添加操作。

需要注意的是,pre 钩子函数只能自定义实例化或保存等方法的前置事件,在其他场景下可能不是我们想要的行为,例如查询、删除等。如果需要对这些操作进行自定义验证,我们可以使用 post 钩子。

2.2.2 使用 post 钩子

post 钩子是在后置钩子函数中执行的,可以在成功保存或者失败添加等事件后进行数据处理。与 pre 钩子不同,post 钩子函数是同步执行的,其参数列表也有所不同:

  • doc:代表操作成功后的文档对象(即保存到数据库后的数据对象);
  • result:代表操作成功的结果,其类型可以是任意值;
  • next:如果有指定,则说明存在下一个中间件函数,可以调用 next() 函数进入下一个函数调用;如果没有指定,则不会执行后面的中间件函数。
  • error:代表操作失败时的错误对象;
  • session:如果开启了会话(session),则会传递会话对象;否则为 undefined。

例如,我们要在保存 user 模型操作成功后,清除一些敏感信息。可以通过 post 中间件函数来实现:

在上述代码中,我们定义了一个 post 中间件函数,监听了 save 事件。在函数中,我们删除了文档对象的 password 属性,并调用了 next 函数,事实上此时可以省略 next 函数,因为 post 钩子的唯一作用就是在成功保存后进行操作。

需要注意的是,如果同时使用了 pre 和 post 钩子函数,则必须在执行前置操作时调用 next() 函数,否则后置操作将不会被执行。

3. 通过 assert 库进行验证

以上介绍了如何使用 Mongoose 自带的 validate 方法和中间件函数来自定义数据字段验证规则。这两种方式都是通过抛出错误的方式来让整个操作失败,然后通过 catch 语句捕捉错误进行处理。但是,有时候直接抛出错误可能不太方便,而且在某些情况下还需要对数据的某些属性进行详细的验证。这种情况下,我们可以使用 Node.js 内置的 Assert 库来进行验证。Assert 库提供了一些方法来判断变量是否符合某种条件,如果不符合,则会抛出异常,否则什么都不会发生。

例如,我们要对一个用户名进行验证,要求其长度在 4~8 个字符之间,且只能包含英文字母和数字。可以使用 assert 库来实现:

-- -------------------- ---- -------
----- ------ - ------------------

-------- ---------------- ---------- -
  -------------------------------------------
    -------- -------- ------ ----- -- --- ---------- ----- --- ---- ------- ------- --- ---------
  --
-

--------------------------- -- --
---------------------------- -- --------------

在上述代码中,我们使用 assert 库的正则表达式方法进行了用户名的验证。如果不符合规则,则抛出一个 AssertionError 异常,将影响到整个执行流程。如果需要自定义 Assertion 类型,则可以通过 define 方法来实现。

4. 总结

在本文中,我们学习了 Mongoose 的数据字段验证机制,介绍了如何在 Schema 中使用 validate 方法和钩子函数来自定义验证规则,同时还介绍了如何使用 Assert 库进行验证。这些方法可以提高我们在实际项目中对数据的安全性进行控制,保证其完整性、可靠性和有效性。需要注意的是,验证规则的复杂度越高,操作的性能就越低,因此在选择验证规则时需要权衡其中的利弊。如果您还有其他问题或者建议,欢迎在评论区留言,与我们分享您的看法。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/6465e7f0968c7c53b0691893

纠错
反馈