如何使用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
相关产品推荐
相关产品推荐

