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

如何在MongoDB中基于不同名称字段执行$merge操作?

问题:MongoDB中为指定文档分配新ID并合并回原集合

我的场景和Stack Overflow上某问题类似但有区别:需要给集合里的部分文档根据旧ID分配新ID。

我原本的思路是:

  • 用聚合操作添加oldId字段保留旧ID
  • 通过函数计算新值并设置_id字段
  • 将处理后的文档合并回原集合(仅部分文档需要调整)

但核心问题是:合并时需要用新文档的oldId匹配原集合的_id,也就是满足$$new.oldId === $_id的条件进行合并,不知道该怎么实现。

尝试过的方法及遇到的问题

  • 尝试在$merge的whenMatched中使用聚合管道,但MongoDB不允许修改用于匹配的字段,而我恰恰需要修改_id。
  • 考虑用常规的updateMany,但触发了错误:

    Uncaught MongoServerError: After applying the update, the (immutable) field '_id' was found to have been altered to _id: [redacted]

当前可行解决方案

我最终采用的方案是去掉$match阶段,调整转换逻辑让无需修改的文档保持ID不变,再用$out替换整个集合,这个方案在我的场景中可行。

完整示例代码:

db.foo.insertMany([
  {_id: 123, description: "This id needs to be changed to 369" },
  {_id: 234, description: "This id needs to be left alone" },
  {_id: 345, description: "This id needs to be left alone" }
]);

print("===========");

db.foo.find({});

print("===========");

db.foo.aggregate([
  {$addFields: {
    oldId: "$_id",
    _id: { $function: {
      body: function(id) {
        if (id === 123) {
          return id * 3;
        } else {
          return id;
        }
      },
      args: ["$_id"],
      lang: "js"
    }}
  }},
  {$out: "foo"}
]);

db.foo.find({});

理想实现方式(寻求更优解)

我不想修改无需调整的文档,希望能用$merge提供的细粒度控制。理想的实现逻辑如下,但不知道如何处理$merge的匹配条件:

db.foo.aggregate([
  {$match:{
    _id: 123
  }},
  {$addFields: {
    oldId: "$_id",
    _id: { $function: {
      body: function(id) {
        return id * 3;
      },
      args: ["$_id"],
      lang: "js"
    }}
  }},
  {$merge: {
    into: "foo",
    on: "$$new.oldId === $_id", // 此处是需要解决的核心问题
    whenMatched: "replace",
    whenNotMatched: "discard"
  }}
]);

内容的提问来源于stack exchange,提问作者SQB

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 17:37:30