mongodb 如何在不同名称的字段上$merge?

qmelpv7a  于 2023-06-22  发布在  Go
关注(0)|答案(1)|浏览(119)

我遇到了一个几乎完全不同于this one的情况。我有一个集合,我必须根据旧的ID分配新的ID。
我想到了使用聚合来实现它,添加一个新字段以在一个名为“oldId”的新字段中保留旧id,然后将_id设置为我的新值(由函数计算)。
然后我想将其合并回集合中(并不是所有文档都在这件事上进行了调整-不要问),但是,是的,有摩擦:我需要合并一边的_id和另一边的oldId
我需要将来自管道的文档合并到$$new.oldId === $_id上的现有集合中。
我该怎么做?
我想到在合并的whenMatched中使用聚合管道,但它不允许修改合并所基于的字段,而这正是我需要做的。
我也想过使用常规的updateMany来实现,但不幸的是
Uncaught MongoServerError: After applying the update, the (immutable) field '_id' was found to have been altered to _id: [redacted]
我最终使用的解决方案是删除$match并修改转换,在某些情况下不使用id,然后使用$out替换整个集合。
Full example of my current solution

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提供的更细粒度的控制。
它看起来像这样:

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", // this is what I'm trying to figure out
    whenMatched: "replace",
    whenNotMatched: "discard"
  }}
]);
pn9klfpd

pn9klfpd1#

原则上可以是这样的:

db.collection.aggregate([
  { $match: { _id: 123 } },
  {
    $merge: {
      into: "collection",
      on: "_id",
      whenMatched: [
        {
          $set: {
            _id: { $function: {
              body: function(id) {
                return id * 3;
              },
              args: ["$_id"],
              lang: "js"
            }}
          }
        }
      ],
      whenNotMatched: "discard"
    }
  }
])

或者这个:

db.collection.aggregate([
  { $match: { _id: 123 } },
  {
    $addFields: {
      newId: { $function: {
        body: function(id) {
          return id * 3;
        },
        args: ["$_id"],
        lang: "js"
      }}
    }
  },
  {
    $merge: {
      into: "collection",
      on: "_id",
      whenMatched: [
        {
          $set: {
            _id: "$$new.newId",
            newId: "$$REMOVE"
          }
        }
      ],
      whenNotMatched: "discard"
    }
  }
])

正如我不止一次告诉你的:你不能修改这_id字段-周期.管道不能修改on字段的值。所以,甚至有两个限制阻碍了你的想法。
你需要插入一个新的_id文件并删除旧的。我不认为你可以用一个命令来完成它。

相关问题