使用Mongoose findOneAndUpdate删除子文档失效该如何解决?
Mongoose findOneAndUpdate 删除关联子文档失效问题解决方案
你代码中存在5处核心错误导致操作不生效:
- Schema 语法错误:定义
unitSchema时,address字段配置结束后缺少逗号,会导致Schema初始化失败,contracts字段无法被正确识别。 - 查询条件字段错误:MongoDB 默认主键字段为
_id,你的查询条件写为{id: req.params.id},在没有自定义id字段的情况下无法匹配到任何父文档,更新操作自然不会执行。 $pull操作写法错误:你的contracts数组存储的是Contract文档的ObjectId值,不是包含id字段的嵌套对象,所以{$pull: {contracts: { id: req.params.cid }}}的匹配规则完全错误,无法命中要移除的关联id。另外req.params拿到的参数是字符串类型,需要显式转为ObjectId才能和数组内的类型匹配。- 异步流程错误:你给路由加了
async修饰,但没有awaitfindOneAndUpdate方法,代码会直接执行redirect跳转,此时更新操作可能还没完成,跳转后看到的还是旧数据。 - 缺少子文档删除逻辑:当前代码仅尝试移除父文档中的关联id,没有调用
Contract集合的删除方法,所以子文档本身不会被删除。
修复后的代码
修正Schema
const unitSchema = new mongoose.Schema({ address: { type: String, required: true }, // 补充缺失的逗号 contracts: [{type: mongoose.Schema.Types.ObjectId, ref: 'Contract'}] });
修正路由逻辑
const mongoose = require('mongoose'); unitRouter.delete('/:id/contracts/:cid', async (req, res) => { try { // 移除父文档中的关联id await Unit.findOneAndUpdate( { _id: req.params.id }, // 改为Mongo默认主键 _id,若自定义id可保留原字段 { $pull: { contracts: mongoose.Types.ObjectId(req.params.cid) } }, // 直接匹配要移除的ObjectId { new: true, runValidators: true } ); // 删除Contract集合中的子文档本身 await Contract.deleteOne({ _id: req.params.cid }); } catch (err) { console.error('操作失败:', err); } // 等待所有异步操作完成后再跳转 res.redirect(`/units/${req.params.id}`); });
内容的提问来源于stack exchange,提问作者priitpätt
相关产品推荐
相关产品推荐

