mongoimport 失败与 "The _id field cannot be changed from" 不一致

mongoimport failing inconsistently with "The _id field cannot be changed from"

我在将数据导入 mongodb 时遇到问题。我有一个这样的 test.json 文件:

{"_id":{"s":{"$numberLong":"38851448"},"a":5},"someKey":"someValue"}
{"_id":{"s":{"$numberLong":"38853194"},"a":5},"someKey":"someValue"}
{"_id":{"s":{"$numberLong":"38760498"},"a":5},"someKey":"someValue"}
{"_id":{"s":{"$numberLong":"39099662"},"a":5},"someKey":"someValue"}
{"_id":{"s":{"$numberLong":"38855558"},"a":5},"someKey":"someValue"}
{"_id":{"s":{"$numberLong":"38760487"},"a":5},"someKey":"someValue"}
{"_id":{"s":{"$numberLong":"38760488"},"a":5},"someKey":"someValue"}
{"_id":{"s":{"$numberLong":"39099663"},"a":5},"someKey":"someValue"}
{"_id":{"s":{"$numberLong":"38851450"},"a":5},"someKey":"someValue"}
{"_id":{"s":{"$numberLong":"38853546"},"a":5},"someKey":"someValue"}

我尝试使用以下命令导入它:

mongoimport --type json --db test --collection coll --file test.json --upsert

导入几乎总是失败并显示相同的错误消息:

2015-08-27T17:02:15.510+0200    error inserting documents: The _id field cannot be changed from {_id: { s: 38851448, a: 5 }} to {_id: { a: 5, s: 38851448 }}.
2015-08-27T17:02:15.511+0200    error inserting documents: The _id field cannot be changed from {_id: { a: 5, s: 38760487 }} to {_id: { s: 38760487, a: 5 }}.

令人沮丧的是,这个错误甚至无法重现。进口商似乎改变了 _id 的属性顺序,但我不知道为什么,这是应该报告还是已知的 BUG?或者有没有 我没有看到一个问题。

我什至尝试更改 _idsa 的顺序,但问题仍然存在。

如果我尝试 运行 使用完全相同的数据文件多次执行完全相同的导入命令,则出现错误的文档会发生多次更改,并且有一次它按预期导入了所有行,但只有一次:

为了完整起见:我在 Mac OS X 10.10.5 上使用 mongo 3.0.5 由自制软件安装。

更新: 我已经与 mongoDB-Team 创建了一张工单:TOOLS-894

更新2:

我尝试不使用 _id,而是使用 id 作为我的唯一键:

{"id":{"s":{"$numberLong":"38851448"},"a":5},"someKey":"someValue"}
{"id":{"s":{"$numberLong":"38853194"},"a":5},"someKey":"someValue"}
{"id":{"s":{"$numberLong":"38760498"},"a":5},"someKey":"someValue"}
{"id":{"s":{"$numberLong":"39099662"},"a":5},"someKey":"someValue"}
{"id":{"s":{"$numberLong":"38855558"},"a":5},"someKey":"someValue"}
{"id":{"s":{"$numberLong":"38760487"},"a":5},"someKey":"someValue"}
{"id":{"s":{"$numberLong":"38760488"},"a":5},"someKey":"someValue"}
{"id":{"s":{"$numberLong":"39099663"},"a":5},"someKey":"someValue"}
{"id":{"s":{"$numberLong":"38851450"},"a":5},"someKey":"someValue"}
{"id":{"s":{"$numberLong":"38853546"},"a":5},"someKey":"someValue"}

并导入:

mongoimport --type json --db test --collection coll --file test.json --upsertFields id

现在我没有收到任何错误,但是在两次导入之后我在集合中有 15 行而不是 10 行。同样是因为 id.

中属性的顺序

从 mongoimport 命令中删除 --upsert 将允许您导入数据。但这揭示了另一个更大的问题 - mongoimport 不会保留您的 _id 字段的键顺序。有时 s 先出现,有时 a。这会使涉及 _id 的每个应用程序操作都乏味且缓慢 - 你不能使用文档文字,你必须使用类似的东西:

db.coll.find({'_id.a': 5, '_id.s': NumberLong("38760488")})

使用嵌入式文档作为 _id 似乎是一种极端情况,没有与此相关的 jira 问题。 _id 类型可以是除数组之外的任何内容,因此它们适用于此用例。批量操作使用与标准写入操作不同的机制,所以......可能是一个错误 - 没有其他人这样做并发现它了吗?

您可能可以使用单独的写入命令(然后使用文档文字作为查询参数)来解决这个问题 - 但您应该这样做吗?无法使用 mongo export/import 进行数据库维护对我来说似乎是一个交易杀手。

另请注意:mongoimport --upsert 将用 "someKey":"someValue" 替换任何现有文档 - 假设这只是一个简化的测试用例。

您可以前往 https://jira.mongodb.org 并注册一个帐户来报告错误。

我尝试过的所有事情都让我相信这是 mongoimport 中的错误,我将其报告给 mongoldb 团队:TOOLS-894

对我有用的解决方法是将文档的唯一键移出 _id 并将其拆分为它们自己的属性,如下所示:

{"s":{"$numberLong":"38851448"},"a":5,"someKey":"someValue"}
{"s":{"$numberLong":"38853194"},"a":5,"someKey":"someValue"}
{"s":{"$numberLong":"38760498"},"a":5,"someKey":"someValue"}
{"s":{"$numberLong":"39099662"},"a":5,"someKey":"someValue"}
{"s":{"$numberLong":"38855558"},"a":5,"someKey":"someValue"}
{"s":{"$numberLong":"38760487"},"a":5,"someKey":"someValue"}
{"s":{"$numberLong":"38760488"},"a":5,"someKey":"someValue"}
{"s":{"$numberLong":"39099663"},"a":5,"someKey":"someValue"}
{"s":{"$numberLong":"38851450"},"a":5,"someKey":"someValue"}
{"s":{"$numberLong":"38853546"},"a":5,"someKey":"someValue"}

这样我就可以像这样导入数据了:

mongoimport --type json --db test --collection coll --upsertFields a,s --file test.json

插入新文档并更新旧文档

更新:

TOOLS-894TOOLS-899 中,mongodb 开发人员描述了另一种解决方法:您可以使用 2.6 版本的 mongoimport,它没有这个错误。或者你可以等待 mongodb 3.0.7 应该包含修复。

更新 2:

MongoDB 的新版本解决了这个问题并按预期工作。