Mongoose 使用中遇到的一些坑及解决方案分享

Mongoose 是 Node.js 中最流行的 MongoDB 驱动器之一。它是一个优秀的对象文档模型(ODM),为我们提供了快速而方便的数据库访问。然而,在 Mongoose 使用的过程中,有些坑是我们不可避免的,接下来我们就来详细了解一下 Mongoose 使用过程中需要注意的坑。

坑一:Schema 字段的默认值

当我们在定义 Mongoose Schema 的时候,如果字段有默认值,那么每次创建这个模型的新实例时,就会将默认值添加到新实例中。示例代码如下:

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

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

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

然而,我们需要注意的是,如果字段的默认值是一个对象或数组,那么这个对象或数组在每个新实例中都将是同一个对象或数组。比如下面这个示例:

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

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

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

在上面的示例中,tags 字段的默认值是一个空数组,然而,当我们创建两个 Post 实例时,它们的 tags 字段实际上引用了同一个数组,改变其中一个 tags 数组的值,两个实例的 tags 值都会发生改变,这是一个十分危险的坑,因此,在设置默认值时需要多加注意。如果默认值是一个对象或数组的话,建议使用函数的方式设定默认值。

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

使用函数的方式设定默认值,每次创建实例的时候都会调用函数生成新的数组,避免了多个实例共享同一个对象的问题。

坑二:Document 的默认方法

在 Mongoose 中,每个文档实例(也就是 Mongoose 中的 Document)都有一些默认方法,例如saveremovevalidate等等。当我们在定义 Schema 的时候,如果自定义了某个字段的一个方法同名,可能会引发一些不可预知的错误。比如下面这个示例:

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

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

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

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

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

在上面的示例中,我们为 UserSchema 中的 validate 字段自定义了一个 validate 方法。然而,在创建 User 实例时,这个实例继承了 Document 中的 validate 方法,在调用自定义的 validate 方法后,user 实例将拥有自定义方法的属性而丢失了原有的 save 等方法。因此,在自定义方法名前,需要先了解Document 中是否包含同名方法。

坑三:Document 数组的 push 方法不触发中间件

在 Mongoose 中,Document 数组的 push 方法并不会触发 prepost 中间件,这可能会导致我们的一些业务逻辑在使用 push 方法后没有传递到中间件中。比如下面这个示例:

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

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

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

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

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

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

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

在上面的示例中,我们为UserSchema注册了prepost两个中间件。因为在 Mongoose 中,数组的 push 方法并不会触发中间件,所以在上面的代码中,如果我们调用leader.followers.push(follower)方法,prepost两个中间件都不会被调用,实际上只有保存到数据库的操作会触发中间件。

如果需要在 push 数组时也调用中间件,我们可以使用 $push 替代数组的 push。

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

在上面的示例中,我们先使用concat方法将 follower 添加到 leader followers 数组中,再使用markModified方法告诉 Mongoose 来检测 followers 数组的更改,接着再保存 leader。这样做的话,prepost中间件会被正常调用。

坑四:Document 数组深度限制

当我们在 Mongoose 操作 Document 数组时,有些操作只能递归地进行一定的深度限制,否则将会造成栈溢出错误。默认情况下,Mongoose 对 Document 数组递归的深度限制为 20 层深度。如果我们需要修改这个限制,可以按照下面这个方式来修改:

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

在上面的示例中,我们将递归的深度限制增加到了 100 层深度。

如果我们在对 Document 数组进行操作时,遇到了栈溢出的错误提示,就要重点注意这个问题。

总结

这篇文章只是介绍了 Mongoose 使用中的一些坑,当然,还有很多没有被提到的知识点。在 Mongoose 的使用过程中,我们还需要注意到一些其他的问题,例如 Mongoose 的连接引用计数、Mongoose 的多模型操作等等。只有通过不断地实践和深入学习,才能在使用 Mongoose 的过程中避免遇到坑,提高我们的开发效率。

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


猜你喜欢

  • 如何在 SASS 中使用命名空间

    在前端开发中,使用 CSS 预处理器可以帮助我们更加高效地编写样式代码。而 SASS 作为其中的一种,其强大的功能和灵活性让它成为了众多前端开发者的偏爱。 其中,命名空间就是 SASS 中十分实用的一...

    1 年前
  • TypeScript 中的模块

    随着前端技术的发展,越来越多的人开始接触 TypeScript,它可以帮助我们更好地管理代码结构和类型,使得前端开发变得更加简单和高效。本文将重点介绍 TypeScript 中的模块,让大家更好地理解...

    1 年前
  • 解决 Tailwind CSS 在 Webpack 中引入失败的问题

    在前端开发中,使用现代化的工具可以提高效率,加速开发进程。Tailwind CSS 是近年来非常流行的 CSS 框架,它可以帮助我们快速构建漂亮而高效的用户界面。然而,在使用 Webpack 打包时,...

    1 年前
  • Kubernetes 集群中的 Docker Registry 搭建及使用

    Docker Registry 是一个用于存储和分发 Docker 镜像的开源项目。在 Kubernetes 集群中,我们可以通过搭建一个私有 Docker Registry,来实现镜像的私有化管理和...

    1 年前
  • 解决 Angular 应用中跨域问题

    什么是跨域问题 在网页中,如果一个页面的 JavaScript 代码想要访问另外一个页面的数据,那么需要浏览器支持跨域访问。所谓跨域,就是指在网络安全限制下,一个网站的文件无法直接访问另外一个网站的文...

    1 年前
  • SQL Server 数据库性能优化指南

    随着科技的发展,数据的重要性越来越受到公司和组织的关注。然而,大量数据的存储和管理也对数据库系统的性能提出了更高的要求。在这篇文章中,我们将提供一些 SQL Server 数据库优化的指南,帮助您提高...

    1 年前
  • Headless CMS 在 Gatsby 站点构建中的实战运用

    前端领域中,如今有的是各种可供选择的内容管理系统(Content Management System,简称 CMS),其中一个最近日渐流行的变种是 Headless CMS。

    1 年前
  • ES2020 BigInt 详解及应用实例

    在 JavaScript 中,数字类型是非常常见的数据类型之一。然而,在进行一个需要极大数字计算的场景中,JavaScript 的数字类型无法完全满足需求。ES2020 版本中新增了 BigInt 类...

    1 年前
  • Sequelize 中如何使用 Promise

    Sequelize 是一个 Node.js 中使用的 ORM(Object-Relational Mapping)框架,可以将 JavaScript 对象和数据库中的表格映射起来。

    1 年前
  • Kubernetes 不同版本之间的升级方法分析

    前言 随着 Kubernetes 的发展壮大,更新换代也越来越频繁。在使用过程中,经常会遇到需要升级 Kubernetes 版本的情况。然而,Kubernetes 的升级并不是一件简单的事情,可能会带...

    1 年前
  • PM2 常见错误:如何解决 PM2 启动应用程序后出现 ENOMEM 错误

    PM2 常见错误:如何解决 PM2 启动应用程序后出现 ENOMEM 错误 什么是 PM2 PM2 是一种使用 Node.js 编写的进程管理器。它可以管理应用程序的启动、运行和停止,并提供了一些实用...

    1 年前
  • 善用 ES10 中的 Object.fromEntries 方法

    在前端开发中,我们经常需要将不同形式的数据转换为 JavaScript 对象。在 ES2019 中,新加了一个非常实用的方法,即 Object.fromEntries(),它可以帮助我们将键值对数组转...

    1 年前
  • Hapi.js+Redis 实现用户在线状态查询 - 解决 Redis 缓存重复读取问题

    Hapi.js+Redis 实现用户在线状态查询 - 解决 Redis 缓存重复读取问题 在实际开发中,我们经常需要查询用户是否在线,以及用户最近的活动时间。如果每个请求都去查询数据库,会造成数据库的...

    1 年前
  • 如何在 React Native 应用程序中使用 LESS?

    如何在 React Native 应用程序中使用 LESS? 在 React Native 开发中,使用 LESS 可以让你更好地管理样式,提高代码的可维护性。本文将详细介绍如何在 React Nat...

    1 年前
  • Custom Elements 中如何处理父组件与子组件通信

    在前端开发中,经常会遇到需要组件间通信的场景。而在使用 Custom Elements 进行组件开发时,如何处理父组件和子组件的通信是一个必须要掌握的技能。下面将介绍通过一些案例来详细探讨如何有效地处...

    1 年前
  • Koa2 中使用 Mongoose 连接 MongoDB 数据库

    前言 在 Web 开发中,数据库是非常重要的一个环节。由于前端技术的不断发展和进步,Web 开发越来越多地融合了前端和后端的技术,因此前端工程师也需要接触和了解数据库的知识和操作。

    1 年前
  • 使用 Deno 中的 fetch API 发送 HTTP 请求时如何正确地处理错误?

    在 Deno 中使用 fetch 函数来发送 HTTP 请求是一个非常方便的方式,但是在实际开发中,我们也需要正确地处理错误以避免不必要的问题。在本文中,我们将讨论如何在 Deno 中正确地处理 fe...

    1 年前
  • PWA 开发中使用 Intersection Observer API 监测元素的最佳实践

    近年来,PWA(Progressive Web App)的开发愈发成为前端界的热门话题。作为一种新型的 web 应用形态,PWA 通过利用浏览器和 Web 技术的最新能力,使得 web 应用具备了原生...

    1 年前
  • Android Material Design 中使用 SwipeRefreshLayout 实现加载更多的方法详解!

    Android Material Design 是 Google 推出的一套全新的视觉设计语言,它采用简洁、平面、直观的设计风格,使用户体验和应用程序功能更为统一一致。

    1 年前
  • 使用 Django 框架构建 RESTful API 的最佳实践

    随着 Web 技术的不断发展,目前前端开发中最为流行的一种方式是使用 RESTful API 与后端进行数据交互。而 Django 作为一款流行且上手容易的 Python Web 框架,也提供了强大的...

    1 年前

相关推荐

    暂无文章