引言
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 中的 _id
,foreignField
指向了 Article Model 中的 author
字段,这样便可以实现从 User Model 中查询到该用户所拥有的所有文章。
2. 将数据在访问时进行格式转换
有时在前端开发中,我们需要将数据在访问时进行格式转换,例如将数据中的时间戳转化为日期格式,或者将单位为分的金额转换为单位为元的金额。此时我们可以使用虚拟属性进行转换。
如下所示:
----- -------- - -------------------- ----- ------------- - --- ----------------- ----- ------- ------ ------ --- ------------------------------------------------- - ------ ----------- - ---------------- --- ----- ------- - ------------------------- --------------- -------------- - --------
在上述代码中,Product Model 中定义了一个名为 priceYuan
的虚拟属性,它被定义为一个 getter 函数。在访问 priceYuan
属性时,getter 函数将原本保存的商品价格进行单位转换,并转化为字符串类型。
虚拟属性的定义方式
在 Mongoose 中,可以使用 schema.virtual()
函数来定义虚拟属性。该函数接受两个参数:
- 属性名称
- 对象字面量,该对象字面量应该至少具有
get
或set
中的一个函数。
下面给出一个虚拟属性的具体定义方式:
----- -------- - -------------------- ----- ------ - ---------------- ----- ------------- - --- -------- ------- ------- ------- ------ --- --------------------------------------------------------- - ------ ----------- - - - - ------------ --- ----- ------- - ------------------------- ---------------
在上述代码中,我们定义了一个名为 concatenatedField
的虚拟属性,该属性的值是 field1
和 field2
连接而成的字符串。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