Mongoose中post update钩子无法访问this._id问题求助
问题原因分析
这个问题其实是Mongoose钩子体系里一个很常见的坑——不同类型的钩子,this的指向完全不一样:
post('save')属于文档类钩子,触发时this指向的是被保存的具体文档实例,所以能直接访问this._id。post('update')属于查询类钩子,触发时this指向的是Mongoose的Query对象(也就是你执行的更新查询本身),而不是被更新的目标文档,自然就没有_id属性啦。
解决方案
根据你的使用场景,这里有几种靠谱的处理方式:
1. 改用findOneAndUpdate的钩子(更推荐)
如果你是用findOneAndUpdate这类方法执行更新,直接用对应的钩子就行,而且能通过第二个参数拿到更新后的文档:
ClientSchema.post('findOneAndUpdate', function(doc) { console.log(doc._id); // 这里能正常获取到文档的_id });
⚠️ 注意:调用findOneAndUpdate时一定要加上{ new: true }选项,这样doc才会是更新后的最新文档。
2. 在update钩子中手动查询目标文档
如果必须用模型层面的update方法,可以通过this.getQuery()拿到更新的查询条件,再手动查询对应的文档:
ClientSchema.post('update', function() { // 获取更新时的查询条件 const query = this.getQuery(); // 根据条件查询文档 Client.findOne(query) .then(doc => { if (doc) { console.log(doc._id); } }) .catch(err => { // 记得处理可能的查询错误 console.error('查询文档失败:', err); }); });
💡 小提示:如果你的更新条件匹配多个文档,findOne只会返回第一个,要是需要处理所有被更新的文档,换成find就行。
3. 先获取文档实例再执行更新
如果业务允许,你可以先查询到目标文档实例,再调用实例的updateOne方法,这样就能用文档类钩子了:
// 先查询到文档实例 Client.findById(targetId).then(client => { // 调用实例的updateOne方法 client.updateOne({ name: '更新后的名称' }); }); // 对应的文档类钩子 ClientSchema.post('updateOne', function() { console.log(this._id); // 这里this是文档实例,能直接拿到_id });
额外小科普
Mongoose的钩子本质上分为两大类:
- 文档钩子:针对单个文档实例的操作(比如
save、实例调用的updateOne、remove等),this始终指向该文档实例。 - 查询钩子:针对模型层面的批量查询/更新操作(比如
update、updateMany、模型调用的findOneAndUpdate等),this指向的是Mongoose的Query查询对象。
内容的提问来源于stack exchange,提问作者JenuRudan
相关产品推荐
相关产品推荐

