我遇到了一个几乎完全不同于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"
}}
]);
1条答案
按热度按时间pn9klfpd1#
原则上可以是这样的:
或者这个:
正如我不止一次告诉你的:你不能修改这
_id
字段-周期.管道不能修改on
字段的值。所以,甚至有两个限制阻碍了你的想法。你需要插入一个新的
_id
文件并删除旧的。我不认为你可以用一个命令来完成它。