Mongoose 中令人迷惑的 Document#populate

在 MongoDB 中,数据可能需要通过多个文档来查询和呈现。按需加载这些数据可以大大提高应用程序的性能,MongoDB 通过 $lookup 操作符支持多文档操作,但也很容易出错。Mongoose 是一个为 Node.js 设计的 MongoDB 对象模型工具,有助于优化这一处理过程。

不过,在 Mongoose 中,有一个名为 Document#populate 的方法,会让人容易迷惑。在这篇文章中,我们将详细分析 Document#populate ,同时提供深度和指导意义。

前期知识准备

在深入 Document#populate 的用法和意义之前,我们需要了解一些前置知识。

Mongoose 的 Schema

在 Mongoose 中,Schema 是一种定义 MongoDB 中文档的结构的指令集。 一个 Mongoose 模型可以通过 Schema 描述一个数据库文档的字段和类型。Schema 有许多选项,例如类型、默认值等。

下面是一个例子的 Schema :

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

关系描述

在 Mongoose 中,除了字段之外,Schema 还可以指定包含其他 Schema 的 refs 。对于关系,通常有以下几种类型:

  • one-to-one
  • one-to-many
  • many-to-many

下面是一个例子,表示 usercomment 之间的 one-to-many 关系:

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

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

上面代码中的 user 是一个 Schema ,该 Schema 包含一个 comments 数组,该数组引用了许多子 comment 文档。子文档 comment 包含一个 user 字段,该字段引用了父文档 user

令人困惑的 Document#populate

在 MongoDB 中,查询一个文档时,通常需要关注该文档的所有引用文档。举个例子,假设我们有一个 article 文档,它包含一个在 user 集合中的作者和一个在 comment 集合中的评论数组。为了从文档中提取引用文档,我们需要使用Mongoose对象模型工具的 populuate() 方法。

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

在这里,如果我们想知道 article 中的所有评论,那么我们需要调用 populate() 方法,并将目标集合名称 'comments' 作为参数传递。但是,您无法通过调用 populate() 来访问深层嵌套的结构。所以我们需要修改 Schema 的内容。

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

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

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

如上面的代码所示,用户和评论之间的关系已被定义,并且已经将之前的评论添加到了文档中,这使得 comments 数组成为了父文档 article 的一部分。现在我们可以使用深层 populate() 查询:

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

现在,新的查询将获取嵌套的 user 数据作为评论数组的一部分。

Document#populate() 方法接受两个参数:

  • path: 字符串,用于定义需要填充的子文档。
  • select: 明确表示控制子文档字段。

如果您需要嵌套的弹出子文档,您需要提供一个对象,而不是字符串。每个该对象包含 pathselect

指南

在了解了 populate() 方法和深层结构嵌套之后,我们现在可以为您提供一些有用的技巧以协助您正确地使用 populate()

性能问题

弹出数据可以降低应用程序在实时操作时的性能。所以在实践中,最好仅在必要的情况下使用它。 如果您调用 populate() 一个引用元素,则使用传递字符串的方式可能是最好的方法。另外,您还应该选择避免嵌套使用的情况,除非您确定需要它。

空引用的问题

空引用会导致查询速度变慢,查询返回的数据也会更大,建议在开发时避免这种情况。其实,我们每次在创建新的 Schema 与 Model 的时候,都应该将创建好的 Schema 和 Model 与 .pre('deleteMany', deleteManyHandler) 方法连接,为什么? 因为当我们删除一个拥有引用的集合数据将会造成异常,如果我们没有进行异常处理,那么将会造成数据残留问题。

下面是异常处理代码:

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

每次在删除拥有多对多集合之间的关系时,我们需要执行这个操作。

禁用自动弹出

当然,有时您可能不希望在查询时自动执行嵌套分裂,这通常是在视图中使用时部分文档需要引用的情况下。在这种情况下,您可以通过将对象标记为 _id 添加可用性。

例如:

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

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

在这里,当您查询 User 时,如果我们使用 populate() 方法填充 viewSchema 中的所有引用,则 someData 将自动弹出。如果只需要 _id ,则可以通过 onlyPopulateId option 进行控制,否则情况下将返回全部数据。

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

通过上面例子,可以看出这将返回带有用户最少数据的完整视图。

总结

弹出文档可以大大提高有关其嵌套数据的查询效率。在 Mongoose 中,你可以通过 .populate() 实现引用文档的填充,从而在单个查询中轻松地访问嵌套的数据。不过,在使用 populate() 时需要注意一些性能问题和异常处理。希望这些技巧会让你的代码更简洁优雅,协助你在Mongoose中更加高效地工作。

来源:JavaScript中文网 ,转载请联系管理员! 本文地址:https://www.javascriptcn.com/post/665587b6d3423812e4a2f8fb


猜你喜欢

  • Babel 环境下配置 File API 的探究

    JavaScript 是一门运行在浏览器环境中的解释性语言。随着前端技术的不断发展,JavaScript 也不断演进和发展。为了让 JavaScript 在浏览器中更加流畅地运行,开发者们需要使用编译...

    5 个月前
  • 省流量!web socket+node.js+socket.io 实现长轮询

    省流量!web socket+node.js+socket.io 实现长轮询 随着智能手机普及和数据流量贵的趋势,越来越多的用户开始考虑如何节省流量。对于移动端网站而言,长轮询可以很好地实现数据及时更...

    5 个月前
  • 如何在 AngularJS 应用中使用 Chai 进行单元测试

    在前端开发中,单元测试是保证代码质量和可靠性不可或缺的一环。Chai 是一个流行的 JavaScript 测试库,它可以与 AngularJS 应用无缝集成,用于编写清晰、动态和可读性强的测试用例。

    5 个月前
  • Redis 水平扩展操作详解

    在实际的前端开发中,我们经常需要使用 Redis 来帮助我们管理缓存、session 等数据,以提高应用程序的性能和扩展性。而当业务量不断增加,单个 Redis 实例的性能已经无法满足需求时,我们需要...

    5 个月前
  • PWA 技术的核心实现,Service Worker 介绍

    随着移动设备的普及,越来越多的网站和应用开始采用 PWA 技术,提供离线访问、快速响应和安全性等优势。而 PWA 技术中的核心实现就是 Service Worker。

    5 个月前
  • RESTful API 中的 HTTP 方法及其应用场景

    RESTful API(Representational State Transfer Application Program Interface,表述性状态转移应用程序接口)是一种基于HTTP协议实...

    5 个月前
  • Docker 容器日志采集及处理

    前言 在工作中,我们经常需要处理容器的日志,如何采集和处理这些日志信息是前端开发人员必须掌握的技能。本文将介绍如何使用 Docker 容器日志采集和处理工具,帮助开发人员更好地处理容器日志。

    5 个月前
  • Redux 插件 redex-logger 源码分析

    Redux 是一种 JavaScript 应用程序状态管理器,Redux 插件 redex-logger 可以帮助开发者更好地理解 Redux 状态管理器的状态变化。

    5 个月前
  • SSE 库原理与源码分析

    SSE(Server-Sent Events,又称为 EventSource)是一种浏览器与服务器之间的消息推送技术,它通过 HTTP 协议的长连接,实现了服务器端向客户端推送数据的能力。

    5 个月前
  • CSS Grid 布局实例 - 用多列联动实现曲线布局

    CSS Grid 布局实例 - 用多列联动实现曲线布局 CSS Grid 布局是一种强大的方式,可以让我们轻松地创建具有复杂布局的网页。在这篇文章中,我们将介绍如何使用 CSS Grid 布局来实现一...

    5 个月前
  • Deno 的常见安全问题及解决方法

    Deno 是一种新兴的 JavaScript 运行环境和开发平台,致力于使 JavaScript 应用程序更安全、更有可靠性。尽管如此,当我们使用 Deno 开发应用程序时,仍然需要小心处理可能出现的...

    5 个月前
  • ES9 — ECMAScript 2018 中加强了正则表达式性能的实现及演示

    随着前端应用越来越复杂,正则表达式作为一项重要的前端技术也变得越来越重要。在 ECMAScript 2018 之前,JavaScript 的正则表达式的性能一直存在问题,很容易导致应用的性能问题。

    5 个月前
  • Cypress 测试自动化 —— 如何等待 XHR 请求完成?

    在前端自动化测试中,等待异步请求完成是非常常见的一个问题。常见的异步请求包括 XMLHttpRequest(XHR)、Fetch 等。而 Cypress 是一个非常流行的前端自动化测试框架,它提供了丰...

    5 个月前
  • Vue.js 如何优雅的处理异步组件加载

    在前端开发中,处理异步组件加载是经常会遇到的问题。Vue.js 是一款流行的 JavaScript 框架,它提供了一种优雅的方式来处理异步组件加载,让我们能够更加高效的开发。

    5 个月前
  • 如何使用 Webpack 快速搭建一个 Vue 应用

    如果你是一个前端开发人员,特别是使用 Vue 框架的开发人员,那么你一定听说过 Webpack 这个构建工具。Webpack 是一个强大的前端构建工具,它可以将你的前端资源(JS、CSS、图片等)进行...

    5 个月前
  • Next.js 中怎样使用 GraphQL

    在现代 Web 开发中,GraphQL 已成为越来越流行的数据查询语言。它通过 API 的方式与客户端交互,而不是简单的 RESTful API。Next.js 是一种灵活的 React 框架,允许我...

    5 个月前
  • Tomcat 性能优化:加快 Java Web 应用的响应速度

    在开发 Java Web 应用时,Tomcat 作为一款常用的 Servlet 容器,负责管理 Web 应用的运行,很大程度上影响着应用的性能和响应速度。为了提高 Java Web 应用的性能,我们需...

    5 个月前
  • 无障碍访问性在在线学习上的实践

    前言 无障碍访问性是指所有人都能够无障碍地访问和使用网站、应用程序和其他技术产品。随着线上学习的发展,无障碍访问性的重要性越来越明显。本文将介绍无障碍访问性在在线学习中的实践经验,并提供相关指导意义。

    5 个月前
  • Material Design 中 TabLayout 使用详解

    在移动端 App 开发中,TabLayout 是一个实用且重要的控件,它可以用来快速地导航和切换不同的视图。Material Design 作为 Google 推出的移动端设计语言,为 TabLayo...

    5 个月前
  • PM2 进程管理之停止 / 删除

    PM2 是一个流行的 Node.js 进程管理工具,可以方便地管理多个 Node.js 应用程序,包括启动、重新启动、停止和删除进程等操作。在本文中,我们将重点介绍如何使用 PM2 停止和删除进程。

    5 个月前

相关推荐

    暂无文章