E11000重复键错误索引:MongoDb异常错误

8

我有一个简单的“用户”集合,目前只有两个文档。

{
    "_id": ObjectId("4ef8e1e41d41c87069000074"),
    "email_id": {
        "0": 109,
        "1": 101,
        "2": 64,
        "3": 97,

{
    "_id": ObjectId("4ef6d2641d41c83bdd000001"),
    "email_id": {
        "0": 109,
        "1": 97,
        "2": 105,
        "3": 108,

现在,如果我尝试在email_id字段上使用{unique:true}创建新索引,MongoDB会投诉我“E11000重复键错误索引:db.users.$email_id dup key:{:46}”。即使在指定{dropDups:true}后仍然出现相同的错误,但是我不认为这是问题所在,因为两个文档都存储了不同的电子邮件ID。我不确定发生了什么,请给予任何指针将不胜感激。
编辑:文档的完整视图:
{
"_id": ObjectId("4ef8e1e41d41c87069000074"),
"email_id": {
 "0": 109,
 "1": 101,
 "2": 64,
 "3": 97,
 "4": 98,
 "5": 104,
 "6": 105,
 "7": 110,
 "8": 97,
 "9": 118,
 "10": 115,
 "11": 105,
 "12": 110,
 "13": 103,
 "14": 104,
 "15": 46,
 "16": 99,
 "17": 111,
 "18": 109
 }
}

{
"_id": ObjectId("4ef6d2641d41c83bdd000001"),
"email_id": {
 "0": 109,
 "1": 97,
 "2": 105,
 "3": 108,
 "4": 115,
 "5": 102,
 "6": 111,
 "7": 114,
 "8": 97,
 "9": 98,
 "10": 104,
 "11": 105,
 "12": 110,
 "13": 97,
 "14": 118,
 "15": 64,
 "16": 103,
 "17": 109,
 "18": 97,
 "19": 105,
 "20": 108,
 "21": 46,
 "22": 99,
 "23": 111,
 "24": 109
 }
}

上述显示中,我省略了一些字段,例如"display_name"、"registered_since"等(我认为它们在引发错误时没有任何作用,如果您仍需要它们,我可能可以将整个文档粘贴在这里)。
我正在使用Erlang MongoDB驱动程序与我的Mongo实例进行通信。正如您所见,所有字段都保存为二进制字节,这就是为什么您在文档中看到了这样奇怪的email_id。
注意:二进制字节格式并非由我的代码逻辑强制执行,我确实将字符串email_id传递到我的bson文档中,但我始终以二进制字节形式查看数据。(可能是因为Erlang MongoDB驱动程序的编写方式,我没有真正调查过,因为我的find()、find_one()和其他查询即使将字段保存为二进制字节也能按预期工作)
编辑:> db.users.findOne()
{
"_id" : ObjectId("4ef6d2641d41c83bdd000001"),
"email_id" : [
    109,
    97,
    105,
    108,
    115,
    102,
    111,
    114,
    97,
    98,
    104,
    105,
    110,
    97,
    118,
    64,
    103,
    109,
    97,
    105,
    108,
    46,
    99,
    111,
    109
],
"display_name" : [
    65,
    98,
    104,
    105,
    110,
    97,
    118,
    43,
    83,
    105,
    110,
    103,
    104
],
"provider" : [
    106,
    97,
    120,
    108,
    46,
    105,
    109
],
"provider_id" : [ ]
}

为什么你的电子邮件看起来这么奇怪? - Sergio Tulentsev
email_id 的值实际上是按照整数键索引的子文档数组吗?还是它们是数组,并且这只是你的编程语言中它们的表示形式?另外,你使用的是哪种编程语言? - dcrosta
2
你需要提供更多信息。看起来你提供的文件是不完整的?'email_id'是否有超过3个元素?也许第46个元素在两个文档中重复了?你是什么时候/如何添加索引的?这是在脚本中还是在mongo shell中?正如@Sergei Tulentsev所说,你应该提供完整的文档视图和最小的能够重现问题的代码。 - lhagemann
@chakram88 我尝试在集合中插入两个文档并创建索引。我已经尝试使用mongo shell和rockmongo管理面板创建索引,但出现了相同的错误。我不确定为什么我的文档中的email_id显示为上述内容。当我将bson文档插入到集合中时,它非常简单,只有{email_id,"me@mail.com"}。 - Abhinav Singh
1
你能否在Mongo shell中粘贴db.users.findOne()的输出?我仍然不确定Mongo是将它们视为数组还是子文档。 - dcrosta
正如 @dcrosta 所说,mongoDB 存储电子邮件的方式似乎非常关键。如果将二进制表示视为子文档,则在您显示的两个文档之间存在多个重复的“键”(尽管“key {:46}” 没有意义)。 - lhagemann
2个回答

5

MongoDB在索引数组字段时,实际上索引的是数组中的每个元素。这样可以高效地支持查找数组中特定元素的查询,例如:

db.users.find({email_id: 46})

由于这个email_id(46)在两个文档中都存在,所以您的唯一索引中存在重复键。

如果您已经设置了dropDups: true,我不确定为什么会出现此错误...您能展示一下如何调用createIndex的代码示例吗?您还应该尝试使用dropDups: 1,因为MongoDB在此上下文中错误地将1true区分对待(请参见https://jira.mongodb.org/browse/SERVER-4562)。


我认为这确实是这种情况。从mongo shell中,dropDups有效,但在mongorock管理面板中失败。我阅读了erlang bson文档,其中写道:“注意,string()将被解释为整数数组。您必须以utf8二进制形式提供字符串,请参见下文。” - 在这种情况下,我不能将我的email_id保存为字符串,因为我希望email_id字段作为一个整体字符串是唯一的,不需要每个字符的唯一性。我认为这真的很混乱,这来自于erlang mongodb驱动程序,如果我将我的email_id字段作为原子传递,它将被保留为完整的字符串,而不是像上面那样逐个字符的数组。 - Abhinav Singh
1
啊,我明白了。所以这些实际上是错误地编码为整数数组的字符串?在这种情况下,您应该确保按照文档关于UTF8二进制的建议进行操作,以便它们在MongoDB中保存为字符串。另外,您使用的是哪个驱动程序? - dcrosta
我正在使用Tony(https://github.com/TonyGen/mongodb-erlang)开发的Erlang MongoDB驱动程序...实际上,我们只需要将字符串作为UTF8二进制传递,如果必须保存为字符串...如果作为Erlang列表传递,则会像片段中显示的那样存储,这将导致唯一键创建错误。我认为可以将此问题标记为关闭。这更多是关于仔细阅读文档,并将字符串作为UTF8二进制传递的问题。 - Abhinav Singh
好的。我对Erlang不是很了解,但听起来你需要使用utf()函数将字符串转换为UTF-8字符串以便在MongoDB中进行存储,否则驱动程序将把它存储为代码点数组(即整数)。一旦你这样做了,在mongo中它将成为一个标量值,而不是一个数组,然后你就可以添加你的唯一索引了。 - dcrosta
大家好,更新一下,如果你正在使用Erlang + MongoDB,请确保所有文档键保存为Erlang二进制术语,这样MongoDB将如其文档中所述选择它们。此外,尽可能在二进制格式(在处理器之间)传递Erlang消息和参数是一个好的(推荐的)实践方法(可能总是)。谢谢! - Abhinav Singh
谢谢提醒,1和true的处理方式不同。我在PHP中也遇到了同样的问题,使用了1但只有true才有效。 - Dukeatcoding

0

对于其他遇到此问题的用户,请使用db.version()检查您的mongo版本。如果您正在运行Mongo 3并尝试使用dropDups清除重复项,则会失败并显示此错误。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接