You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将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);

逻辑说明

  1. 移除指定ID:用$filter替代$pull,分别处理顶层img(元素为带_id的对象)和tar子文档的img(元素为纯ObjectId),过滤掉目标ID。
  2. 清理顶层空数组:通过条件式$unset,当img数组为空时直接移除该字段。
  3. 清理tar子文档空数组:遍历tar数组,对每个子文档判断img是否为空,若是则用$$REMOVE移除该字段,否则保留原内容。

内容的提问来源于stack exchange,提问作者Bear Bile Farming is Torture

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 19:35:41