在 MongoDB 的 Node.js 驱动 Mongoose 中,虚拟属性是一种模式属性,在对文档进行查询或者保存时会自动进行计算或者转换,但它不会在 MongoDB 中存储。这种特性在很多场景下非常有用,它可以给抽象属性和逻辑增加一个新的维度。
基本概念
在 Mongoose 中,虚拟属性的定义非常简单,我们可以通过在 Schema 中调用 virtual()
方法来声明一个虚拟属性。下面是一个示例:
-- -------------------- ---- ------- --- ------------ - --- -------- ---------- ------- --------- ------ --- ----------------------------------------------- - ------ -------------- - - - - -------------- --- --- ------ - ------------------------ -------------- --- ---- - --- -------- ---------- ------- --------- ----- --- --------------------------- -- ---- ---
可以看出,虚拟属性并不存储在 MongoDB 中,而是在运行时(取值时)计算得到。虚拟属性有两种类型:getter
和 setter
,它们分别对应着一个属性值的读取和设置。
虚拟属性类型
Getter
Getter 是一个没有 setter 的虚拟属性类型。当我们在代码中访问该属性时,Mongoose 会执行 get
函数来获取该值。我们可以使用 get
函数返回计算过的值,也可以利用它进行一些复杂的运算、逻辑判断等处理。
下面的例子展示如何计算一个用户文档的年龄:
-- -------------------- ---- ------- --- ---------- - --- -------- ---------- ---- --- ---------------------------------------- - --- -------- - ---------- - ------------------------- --- ------- - --- --------------- ------ --------------------------------- - ------ --- --- ---- - ---------------------- ------------ --- --- - --- ------ ---------- --- ---------- -- -- --- --------------------- -- --
Getter 虚拟属性有一个非常重要的特性,它们可以通过虚拟属性计算,这对于需要频繁执行复杂计算的情况非常有用。而且 Getter 属性的计算可以依赖其他属性,方便我们进行维护和修改。
Setter
Setter 是一个没有 getter 的虚拟属性类型。当我们在代码中设置该属性时,Mongoose 会执行 set
函数,并返回一个新的属性值。Setter 有一个非常重要的作用,它可以用来将外部数据格式化为符合 Schema 规范的格式。
下面的例子展示了一个字符串去除空格的 setter:
-- -------------------- ---- ------- --- ------------------ - --- -------- -------- - ----- ------- ----- --------- ------ ------- -- -------- ------ --- ------------------------------------------------------- - -- ------- --- --- --------- ------ --- ------ ----------- --- --- ------------ - ------------------------------ -------------------- --- --- - --- -------------- -------- ------ -------- - ------ ------ - --- ------------------------- -- ------- -------
这个 setter 可以用来格式化一个消息,也可以用来进行格式校验或转换。Setter 属性还有一个重要的应用场景,就是用来处理外部 API 或者用户输入的数据,保证数据都符合指定格式。
虚拟属性选项
ref
在 Mongoose 中,虚拟属性可以通过 ref 选项关联到其他文档,从而实现文档间关联。ref 选项用来指定被关联文档的 model,支持 string 形式和 objectid 形式。
下面的例子展示了如何在 Mongoose 中关联两个文档:
-- -------------------- ---- ------- --- ----------- - --- -------- --------- - ----- ------------------ ---- ---------- -- -------- - ----- ------------------ ---- --------- -- ------ ------ --- --- -------------- - --- -------- ----- ------- ------ ------- ------ ------ --- ----------------------------------- - ---- -------- ----------- ------ ------------- ---------- --- --- ----- - ----------------------- ------------- --- ------- - ------------------------- --------------- --- -------- - -------------------------- ---------------- --- ---- - --- ---------- ----- ------- ------ ------------------- ------ -------- ---------- --- ----- - --- --------- ----- -------- ------ -- ---------- --- ---------- - --- ------- --------- --------- -------- ---------- ------ ----------- ---------- ------------------ ----- ------ ------------------------------------------- --------- - ------------------------------------------- -- ----- ---
这个例子展示了如何通过虚拟属性 ref 将 Customer 和 Order 关联起来。我们使用 localField
和 foreignField
选项分别指定了关联的本地字段和外部字段。这样,我们就可以在查询 Customer 时直接获取它的订单列表。
localField 和 foreignField
在 ref 选项中,我们使用了两个额外的选项:localField
和 foreignField
。它们描述了两个文档间关联的字段。
localField
:用于指定本 model(即虚拟属性所属的 model)中用于与外部 model 进行关联的字段名称。默认值为 '_id'。foreignField
:用于指定与外部 model 关联的字段名称(即外部 model 中要关联的字段)。默认值为 '_id'。
在关联两个文档时,我们经常需要在查询时使用 populate()
方法,这个方法可以将虚拟属性关联的文档一并查询出来,从而避免了多次查询带来的性能损失。
总结
虚拟属性是 Mongoose 中非常有用的功能,它可以用来处理文档间的关联、逻辑计算和数据格式转换等问题。在使用虚拟属性时,需要特别注意一些选项(如 ref
、localField
和 foreignField
),以及虚拟属性类型(如 getter 和 setter)的区别。同时,还需要充分理解虚拟属性的特性和使用场景,以便更好的利用它们。
来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/653e69377d4982a6eb7e7b9c