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


纠错
反馈