初学者必读:Mongoose 中的虚拟属性详解

引言

Mongoose 是 Node.js 操作 MongoDB 的一个 Object Document Mapping(ODM) 模块,它能够帮助我们更简单和方便的操作 MongoDB 数据库,包括对数据的增删改查、中间件等功能。

Mongoose 中的虚拟属性是一个非常强大的特性,它可以让我们在查询 Mongoose Model 时动态生成一个属性值,从而可以解决多个 Model 之间的关联查询以及数据格式的转换等问题。本篇文章将对 Mongoose 中的虚拟属性进行详细的介绍,包括使用场景、定义方式、实现原理等。

虚拟属性的使用场景

虚拟属性在 Mongoose 中一般用于以下两种情况:

1. 处理多个 Collection 的关联查询

在前端开发中,经常需要进行多个 Collection 的关联查询,例如需要查询一个用户的基本信息以及其所拥有的多个文章,这时通常需要执行两个查询操作,即首先查询用户 Collection 获取用户基本信息,再查询文章 Collection 获取该用户所拥有的所有文章。

这样的数据查询会对数据库产生较大的压力,因此人们在这种情况下往往会选择在一个 Collection 中将所有的信息存储下来,这样查询的时候只需要查询一次即可。

但是如果我们不使用虚拟属性,而是将所有的信息存储在一个 Collection 中,这可能会导致数据变得非常冗余,以及一些字段无法正常记录历史数据。

在这种情况下,我们可以将相关的 Model 使用虚拟属性进行关联,以此达到不冗余数据的目的,如下所示:

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

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

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

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

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

在上述代码中,User Model 中定义了一个名为 articles 的虚拟属性,它通过 ref 指向了 Article Model,localField 指向本 Model 中的 _idforeignField 指向了 Article Model 中的 author 字段,这样便可以实现从 User Model 中查询到该用户所拥有的所有文章。

2. 将数据在访问时进行格式转换

有时在前端开发中,我们需要将数据在访问时进行格式转换,例如将数据中的时间戳转化为日期格式,或者将单位为分的金额转换为单位为元的金额。此时我们可以使用虚拟属性进行转换。

如下所示:

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

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

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

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

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

在上述代码中,Product Model 中定义了一个名为 priceYuan 的虚拟属性,它被定义为一个 getter 函数。在访问 priceYuan 属性时,getter 函数将原本保存的商品价格进行单位转换,并转化为字符串类型。

虚拟属性的定义方式

在 Mongoose 中,可以使用 schema.virtual() 函数来定义虚拟属性。该函数接受两个参数:

  1. 属性名称
  2. 对象字面量,该对象字面量应该至少具有 getset 中的一个函数。

下面给出一个虚拟属性的具体定义方式:

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

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

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

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

在上述代码中,我们定义了一个名为 concatenatedField 的虚拟属性,该属性的值是 field1field2 连接而成的字符串。getter 函数中的 this 关键字指向调用该属性的 Model 实例。

另外,虚拟属性的 set 函数用于修改虚拟属性的值。与 get 函数类似,set 函数需要接受一个参数,它代表了设置的值,并且该函数必须返回新的属性值。

虚拟属性的实现原理

在 Mongoose 中,虚拟属性是通过创建一个 Object.defineProperty() 的 getter 或 setter 来实现的。Object.defineProperty() 是 JavaScript 中一种用于更改对象属性的特性的方法,可以实现定义 getter 和 setter。

Mongoose 中,当我们定义一个虚拟属性时,该属性并不会被存储在数据库中,而是每次在访问该属性时,都会触发 Mongoose Model 中 defineProperty 函数中的 getter 函数,自定义该属性的值并返回。setter 函数则同理。

通过这种方式,我们可以在调用 Mongoose 数据库时,动态地为数据添加属性和方法。

结论

虚拟属性是 Mongoose 提供的一个非常强大的功能,它可以帮助我们解决多个 Collection 的关联查询以及数据格式的转换等问题。它通过自定义一个 Object.defineProperty() 作为属性的 getter 和 setter 函数,实现了自定义 Model 的属性和方法,具有非常灵活的使用方式和丰富的应用场景。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/6736f766317fbffedf071a25