为什么.findByIdAndUpdate绕过mongoose中间件?

Mic*_*ael 4 javascript mongoose mongodb node.js

我在这里搜索过这个问题,但作为初学者,答案有点复杂,有点超出了我的理解范围。我正在使用 bcrypt 来散列密码,并设置了我的架构,以允许我使用中间件来查看用户是否在散列密码之前修改密码(无论是在初始创建还是更新时)。

在后路由上没有问题,但如果我使用补丁路由,就会出现问题,并且我的中间件不会运行。

有人可以帮助我以更简单的方式(即简单的英语)理解为什么它绕过猫鼬吗?:

const user = await User.findByIdAndUpdate(req.params.id, req.body, { new: true, runValidators: true })
Run Code Online (Sandbox Code Playgroud)

但这是有效的:

const user = await User.findById(req.params.id)

updates.forEach((update) => user[update] = req.body[update])
await user.save()
Run Code Online (Sandbox Code Playgroud)

Akr*_*ion 5

这非常简单:您想要的中间件类型(称为query middleware)仅支持/触发某些方法。例如来自文档

以下模型和查询功能支持查询中间件。在查询中间件函数中,this指的是查询。

  • 数数
  • 删除很多
  • 删除一个
  • 寻找
  • 找一个
  • 查找并删除
  • 查找并删除
  • 查找并更新
  • 消除
  • 更新
  • 更新一
  • 更新很多

所以基本上您使用的方法预计不会触发任何中间件。您必须使用findOneAndUpdateupdateupdateOneupdateMany来执行此操作。

在你的第二种情况下,它确实有效。这是因为您实际上正在使用文档中间件。

Mongoose 有 4 种类型的中间件:文档中间件、模型中间件、聚合中间件和查询中间件。文档中间件支持以下文档功能。在文档中间件功能中,this 指的是文档。

文档中间件受以下支持:

  • 证实
  • 节省
  • 消除
  • init (注意:init 挂钩是同步的)

如您所见,save受支持,因此中间件会触发。