如何在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
相关产品推荐
相关产品推荐

