2

我之前采取了一条捷径,并通过连接各个字段来创建我的 Mongo 数据库的主键以创建一个“唯一 id”

我现在想将其更改为实际使用 ObjectId。最好的方法是什么?我有略多于 3M 的文档,并希望这尽可能减少破坏性。

一种简单的方法是将站点关闭一段时间,然后将每个文档从一个使用 ObjectIds 的文档复制到另一个文档,但如果可以的话,我想保持应用程序运行。我想一种方法是在迁移发生时同时写入一段时间,但这需要我有两个相似的代码库,所以我想知道是否有办法避免这一切。

提供一些附加信息:它只是一个未被任何其他人引用的集合。我有另一个 MySQL 数据库,其中包含一些用于创建从该 MongoDB 集合读取的查询的值。

我正在使用 PyMongo/Mongoengine 库从 Python 与 MongoDB 进行交互,我不知道是否可以只更改集合的主键。

4

1 回答 1

3

如果您的网站没有自行关闭,则不应以任何理由关闭您的网站。:)

无论您拥有多少百万条记录,问题的解决方案都取决于您如何使用您的 id。

如果您使用这些 id 交叉引用不同集合中的文档,那么对于每个更新的对象,您将更新引用该对象的所有其他对象。

作为第一步,您的系统应该更新以停止以旧方式创建新对象。如果您的系统允许您轻松执行此操作,那么您可以非常轻松地更新数据库。如果这个改变不容易做,那么你的系统有一些架构问题,你应该首先改变它。如果是这种情况,请更新您的问题,以便我更新我的答案。

由于我对您的应用程序和数据一无所知,因此我所说的将过于笼统。我们将要更新的集合称为 coll_bad_id。此集合中的每个项目都在 coll_poor_guy 和 coll_wisdom_searcher 等其他集合中引用。我将如何做到这一点是一次运行 coll_bad_id 一项,如下所示:

1. read one item
2. update _id with new style of _id
3. insert item back to collection
    -- now we have two copies of the same item one with old-style id, one with new
4. update each item referencing this to use new style id
5. remove the duplicate item with old-style id from collection

您应该记住的一件事是,bson ObjectId 保存的日期/时间数据非常有用。由于您在一天内重建了所有这些对象,因此您的 ObjectId 不会反映这些项目的正确创建时间。对于新添加的项目,他们会。您可以将第一个新添加的项目作为具有正确创建时间的 id 的项目的里程碑。

更新:在 Mongo shell 上运行的代码示例。这不是最有效的方法;但是运行起来是安全的,因为我们在使用新的 _id 重新添加它们之前不会删除任何内容。通过在 find() 调用中添加查询,可以更好地做到这一点。

var cursor = db.testcoll.find()

cursor.forEach(function(item) {
    var oldid= item._id; // we save old _id to use for removal below.
    delete item._id; // When we add an item without _id, Mongo creates a unique _id.
    db.testcoll.insert(item); // We add item without _id.
    db.testcoll.remove(oldid); // We delete the item with bad _id.
});
于 2012-07-08T16:39:58.727 回答