You need to enable JavaScript to run this app. 如何使用Mongoose中间件在文档更新保存前修改终端用户请求体
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Mongoose中间件在文档更新保存前修改终端用户请求体

Mongoose 在updateOne钩子中修改待更新字段的实现方案

核心问题说明

save中间件中的this指向待保存的文档实例,可以直接通过this.字段名读写属性。但updateOne属于查询类中间件,this默认指向Query查询对象而非文档实例,因此你示例中直接修改this.password的写法无法生效。

推荐实现(无需额外查库,性能最优)

通过查询对象自带的getUpdate()方法获取终端用户提交的待更新请求体,修改完成后再通过setUpdate()回写即可生效:

schema.pre('updateOne', async function () {
  // 获取待更新的字段集合
  const updatePayload = this.getUpdate();
  // 仅当请求体携带password字段时执行加密,避免重复加密数据库中已有的密码
  if (updatePayload.password) {
    const salt = await bcrypt.genSalt();
    const hashedPassword = await bcrypt.hash(updatePayload.password, salt);
    // 兼容带$set操作符的更新场景(绝大多数update调用默认会封装$set)
    if (updatePayload.$set) {
      updatePayload.$set.password = hashedPassword;
    } else {
      updatePayload.password = hashedPassword;
    }
    // 回写修改后的更新参数
    this.setUpdate(updatePayload);
  }
});

该实现同时适配findOneAndUpdate、findByIdAndUpdate等底层调用updateOne的更新方法,无需重复编写中间件逻辑。

备选实现(需查库,适用于依赖原有文档属性的场景)

如果你需要基于文档原有字段做逻辑判断,可以先查询出完整文档实例再处理,会多一次数据库查询开销:

schema.pre('updateOne', async function () {
  // 查询待更新的文档实例
  const targetDoc = await this.model.findOne(this.getQuery());
  const updatePayload = this.getUpdate();
  if (updatePayload.password) {
    const salt = await bcrypt.genSalt();
    targetDoc.password = await bcrypt.hash(updatePayload.password, salt);
    // 把修改后的文档属性合并到更新参数中
    this.setUpdate({ $set: targetDoc.toObject() });
  }
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.14 03:27:03