如何将MongoDB多更新查询简化为单条嵌套数组查询?
数据结构 Schema
{ img: // 至少包含1个ObjectId的数组;若字段缺失则表示数组为空 tar: [ { img: // 至少包含1个ObjectId的数组;若字段缺失则表示数组为空 }, { img: // 至少包含1个ObjectId的数组;若字段缺失则表示数组为空 }, ... ] }
原删除照片的查询逻辑
以下是用于删除指定照片的逻辑,该照片的ObjectId可能存在于顶层img数组,也可能存在于部分tar子文档的img数组中:
await mongo_tran_ses.withTransaction(async () => { // 从顶层img数组和所有tar子文档的img数组中移除匹配req.params._id的ObjectId await user.updateOne( { _id: ObjectId(req.user._id) }, { $pull: { img: { _id: { $eq: ObjectId(req.params._id) } }, "tar.$[].img": { $eq: ObjectId(req.params._id) }, }, }, { session: mongo_tran_ses } ); // 若tar子文档的img数组变为空,则移除该img字段 await user.updateOne( { _id: ObjectId(req.user._id), }, { $unset: { "tar.$[element].img": "", }, }, { arrayFilters: [{ "element.img": { $size: 0 } }], session: mongo_tran_ses, } ); // 若顶层img数组变为空,则移除该img字段 await user.updateOne( { _id: ObjectId(req.user._id), img: { $size: 0 }, }, { $unset: { img: undefined, }, }, { session: mongo_tran_ses } ); }, tran_option);
需求目标
将上述三个updateOne查询合并为单条update查询完成操作。
合并后的解决方案
可以利用MongoDB的聚合管道式更新串联多步操作,在单条update中完成所有逻辑:
await mongo_tran_ses.withTransaction(async () => { await user.updateOne( { _id: ObjectId(req.user._id) }, [ // 第一步:移除顶层img和所有tar.img中匹配的ObjectId { $set: { img: { $filter: { input: "$img", cond: { $ne: ["$$this._id", ObjectId(req.params._id)] } } }, tar: { $map: { input: "$tar", as: "item", in: { ..."$$item", img: { $filter: { input: "$$item.img", cond: { $ne: ["$$this", ObjectId(req.params._id)] } } } } } } } }, // 第二步:清理顶层空img数组(转为字段缺失) { $unset: { img: { $eq: ["$img", []] } } }, // 第三步:清理tar子文档中的空img数组(转为字段缺失) { $set: { tar: { $map: { input: "$tar", as: "item", in: { $mergeObjects: [ "$$item", { $cond: [{ $eq: ["$$item.img", []] }, { img: "$$REMOVE" }, {}] } ] } } } } } ], { session: mongo_tran_ses } ); }, tran_option);
逻辑说明
- 移除指定ID:用
$filter替代$pull,分别处理顶层img(元素为带_id的对象)和tar子文档的img(元素为纯ObjectId),过滤掉目标ID。 - 清理顶层空数组:通过条件式
$unset,当img数组为空时直接移除该字段。 - 清理tar子文档空数组:遍历
tar数组,对每个子文档判断img是否为空,若是则用$$REMOVE移除该字段,否则保留原内容。
内容的提问来源于stack exchange,提问作者Bear Bile Farming is Torture
相关产品推荐
相关产品推荐

