You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mongoose pre('update')中间件失效求助:修改密码时无法加密

解决Mongoose pre('update')中间件不生效的问题

嘿,我来帮你搞定这个Mongoose中间件的问题!先给你拆解下问题根源,再给你靠谱的解决方案:

为啥pre('update')不生效?

你得先搞懂Mongoose里这两个钩子的本质区别:

  • pre('save')是针对单个文档实例的操作,比如你新建用户或者先查出来文档再修改保存,this直接指向那个文档对象,所以你能直接修改this.password,加密逻辑自然生效。
  • 但pre('update')(包括updateOne、findOneAndUpdate这类批量/单条更新操作)不一样,这里的this是查询操作对象,不是你要更新的文档实例。而且默认情况下,这类钩子不会像save那样触发文档级的处理,再加上你代码里直接用了未定义的password变量,这就导致加密逻辑根本没跑起来。

另外你原代码里在pre('update')里调用this.update()的写法也有问题,这会触发无限循环,完全没必要这么做。

靠谱的解决方案

我推荐两种方案,按需选择:

方案1:用pre('findOneAndUpdate')(更常用)

如果你是用findByIdAndUpdate或者findOneAndUpdate来修改用户资料(这是最常见的场景),用这个钩子就对了。它能让你获取到要更新的数据,然后直接修改加密:

userSchema.pre('findOneAndUpdate', function(next) {
  // 从更新操作里拿到新密码
  const newPassword = this.getUpdate().$set?.password;
  if (newPassword) {
    // 加密后替换原更新值
    this.getUpdate().$set.password = bcrypt.hashSync(newPassword, bcrypt.genSaltSync(8));
  }
  next();
});

方案2:修复pre('update')的写法

如果你一定要用pre('update'),得从查询对象的_update属性里拿更新数据,调整成这样:

userSchema.pre('update', function(next) {
  const newPassword = this._update.$set?.password;
  if (newPassword) {
    this._update.$set.password = bcrypt.hashSync(newPassword, bcrypt.genSaltSync(8));
  }
  next();
});

额外提醒

  • 如果你是先把用户文档查出来,修改密码后再调用save(),那触发的是pre('save'),你的原逻辑本来就没问题,不用改。
  • 加密时可以去掉第三个null参数,bcrypt.hashSync只需要密码和盐值两个参数就够了。

内容的提问来源于stack exchange,提问作者Scott Kim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:05:47