MongoDB在使用嵌入对象作为键时存储重复的对象键?

时间:2013-11-20 20:11:17

标签: mongodb pymongo

我有mongo db collection,我用自己的对象键覆盖_id键,而不是让mongo使用ObjectId str。

我的文档对象是这样的,

{'_id': {
     'recipient': 'some-string',
     'my-id': 'some str',
      },
 'data': {...}
 }

出于某种原因,我可以在使用嵌入式文档时存储重复文档,因为它们是_id键。

我没有收到重复的密钥错误,当我upsert我的旧文档时,不会更新。不确定是什么导致了这一点。根据mongodoc,我可以使用嵌入对象作为键。

修改1

以下是来自mongo shell的示例查询

  

> dups = db.update_events.find({“timestamp”:1384890772.02277})。toArray()

[
    {
    "_id" : {
        "campaign-id" : "5982",
        "message-id" : "123@x.mailgun.org",
        "event" : "delivered",
        "recipient" : "a@a.com"
    },
    "timestamp" : 1384890772.02277,
    "campaign-id" : "5982",     
    "event" : "delivered",
    "campaigns" : [ ],
    "delivery-status" : {
        "description" : null,
        "message" : "",
        "code" : 0
    },
    "message" : {
        "headers" : {
        },
        "size" : 2885,

        "attachments" : [ ]
    },
    "dealership" : "RuHOYkYvwh",
    "tags" : [
        "RuHOYkYvwh"
    ],
    "flags" : {
        "is-system-test" : false,
        "is-authenticated" : true,
        "is-test-mode" : false
    }
},
{
    "_id" : {
        "recipient" : "a@a.com",
        "message-id" : "123@x.mailgun.org",
        "event" : "delivered",
        "campaign-id" : "5982",
    },
    "delivery-status" : {
        "description" : null,
        "message" : "",
        "code" : 0
    },
    "message" : {
        "attachments" : [ ],
        "recipients" : [
        ],
        "size" : 2885,
        "headers" : {
        }
    },
    "campaign-id" : "5982",
    "tags" : [
        "RuHOYkYvwh"
    ],
    "campaigns" : [ ],
    "event" : "delivered",
    "timestamp" : 1384890772.02277,
    "flags" : {
        "is-system-test" : false,
        "is-test-mode" : false,
        "is-authenticated" : true
    },
    "dealership" : "RuHOYkYvwh"
}
]

> dups.length
2

这是我用来插入它的python代码,

MyCollection.update(item, item, upsert=True)

其中'item'是一个带有'_id'的python dict。

3 个答案:

答案 0 :(得分:3)

问题是属性的顺序,即您的第一个文档是:

"_id" : {
    "campaign-id" : "5982",
    "message-id" : "123@x.mailgun.org",
    "event" : "delivered",
    "recipient" : "a@a.com"
},

你的第二个:

"_id" : {
    "recipient" : "a@a.com",
    "message-id" : "123@x.mailgun.org",
    "event" : "delivered",
    "campaign-id" : "5982",
},

MongoDB实际上将它们视为两个不同的对象。这就是为什么它们不是重复的原因。前段时间有一个关于这个问题的争论很大,关于这种情况是多么愚蠢,并且在某个地方有一个JIRA,但是,现在我的搜索能力让我失望。

修改

下划线问题是python dicts没有排序,如果你想让它正常工作,你需要考虑别的东西。

答案 1 :(得分:1)

你在某处犯了错误。这是不可能的。 _id键在任何情况下都是唯一的。

显示您的代码,该代码不会引起重复键错误,因为此处显示错误:

db.a.remove()
db.a.insert({_id : {'recepient' : 1, 'my-id' : 2}, 'data' : 'aaa'})
db.a.insert({_id : {'recepient' : 1, 'my-id' : 2}, 'data' : 'bbb'})
  

E11000重复键错误索引:a.a。$ id dup key:{:{recepient:   1.0,my-id:2.0}}

db.a.insert({_id : {'recepient' : 1, 'my-id' : 3}, 'data' : 'bbb'})

请注意,整个值应该是唯一的,而不仅仅是您的my-id或recepient。

P.S 您无法更新_id密钥,因此以后您将无法更改收件人或my-id。

答案 2 :(得分:1)

Python不保证字典中键的顺序, 但MongoDB确实关心订单。插入或查询时的不同顺序意味着Sammaye所描述的不同文档。

您可以通过以下方式解决该问题:

a)使用Python的collection.OrderedDict(2.7中的新内容)

http://docs.python.org/2/library/collections.html#collections.OrderedDict

b)使用PyMongo的bson.son

http://docs.python.org/2/library/collections.html#collections.OrderedDict

使用上述任一对象创建'_id'键,插入文档中的键将与您在Python代码中使用的顺序相同。