如何更新一个 MongoDB 文档的 _ id?

我想更新一个文件的 _id字段。我知道这不是很好的练习。但出于技术原因,我需要更新一下。

如果我尝试更新它,我会得到:

db.clients.update({ _id: ObjectId("123")}, { $set: { _id: ObjectId("456")}})


Performing an update on the path '_id' would modify the immutable field '_id'

更新被拒绝了,我该怎么更新呢?

150140 次浏览

无法更新。必须使用新的 _id保存文档,然后删除旧文档。

// store the document in a variable
doc = db.clients.findOne({_id: ObjectId("4cc45467c55f4d2d2a000002")})


// set a new _id on the document
doc._id = ObjectId("4c8a331bda76c559ef000004")


// insert the document, using the new _id
db.clients.insert(doc)


// remove the document with the old _id
db.clients.remove({_id: ObjectId("4cc45467c55f4d2d2a000002")})

你也可以使用一个循环(基于 Niels 的例子)来完成整个集合:

db.status.find().forEach(function(doc){
doc._id=doc.UserId; db.status_new.insert(doc);
});
db.status_new.renameCollection("status", true);

在本例中,UserId 是我想要使用的新 ID

如果想在同一个集合中重命名 _ id (例如,如果想给 some _ ids 加前缀) :

db.someCollection.find().snapshot().forEach(function(doc) {
if (doc._id.indexOf("2019:") != 0) {
print("Processing: " + doc._id);
var oldDocId = doc._id;
doc._id = "2019:" + doc._id;
db.someCollection.insert(doc);
db.someCollection.remove({_id: oldDocId});
}
});

如果(doc. _ id。IndexOf (“2019:”) != 0){ ... 需要防止无限循环,因为 forEach 选择插入的文档,甚至通过使用 。快照()方法。

在这里,我有一个解决方案,避免多个请求,循环和旧的文档删除。

您可以很容易地使用诸如 _id:ObjectId()之类的东西手动创建一个新想法 但是知道如果丢失 Mongo 将自动分配 _ id,您可以使用聚合来创建一个包含文档中所有字段的 $project,但是省略 field _ id。然后可以用 $out保存它

所以如果你的文件是:

{
"_id":ObjectId("5b5ed345cfbce6787588e480"),
"title": "foo",
"description": "bar"
}

那么你的问题将是:

    db.getCollection('myCollection').aggregate([
{$match:
{_id: ObjectId("5b5ed345cfbce6787588e480")}
}
{$project:
{
title: '$title',
description: '$description'
}
},
{$out: 'myCollection'}
])

您还可以从 MongoDB 指南针或使用命令创建一个新文档,并设置所需的 specific _id值。

作为对上述答案的一个很小的改进,我建议使用

let doc1 = {... doc};

那么

db.dyn_user_metricFormulaDefinitions.deleteOne({_id: doc._id});

这样我们就不需要创建额外的变量来保存 old _ id。

稍作修改的@Florent Arlandis 示例,其中我们从文档中的另一个字段插入 _ id:

 > db.coll.insertOne({ "_id": 1, "item": { "product": { "id": 11 } },   "source": "Good Store" })
{ "acknowledged" : true, "insertedId" : 1 }
> db.coll.aggregate( [ { $set: { _id : "$item.product.id" }}, { $out: "coll" } ]) // inserting _id you want for the current collection
> db.coll.find() // check that _id is changed
{ "_id" : 11, "item" : { "product" : { "id" : 11 } }, "source" : "Good Store" }

不要像@Florent Arlandis 的回答那样使用 $match过滤器 + $out,因为 $out 在插入聚合结果之前完全删除了 收藏品中的数据,所以实际上你将丢失所有与 $match过滤器不匹配的数据