为什么db.insert(dict)在使用pymongo时将_id键添加到dict对象

时间:2014-06-27 12:38:45

标签: python mongodb dictionary pymongo

我正在以下列方式使用pymongo:

from pymongo import *
a = {'key1':'value1'}
db1.collection1.insert(a)
print a

打印

{'_id': ObjectId('53ad61aa06998f07cee687c3'), 'key1': 'value1'}
控制台上的

。 我知道_id被添加到mongo文档中。但为什么这也添加到我的python字典中呢?我不打算这样做。我想知道这是什么目的?我可以将此字典用于其他目的,并将字典更新为将其插入文档的副作用?如果我必须将这个字典串行化为一个json对象,我会得到一个

ObjectId('53ad610106998f0772adc6cb') is not JSON serializable

错误。插入函数不应该在将文档插入数据库时​​保持字典的值相同。

5 个答案:

答案 0 :(得分:1)

与其他许多数据库系统一样,Pymongo会在插入数据后立即添加从数据库中检索数据所需的唯一标识符(如果在内容中插入两个具有相同内容{'key1':'value1'}的词典,会发生什么情况。数据库?你如何区分你想要这个一个而不是那个一个?)

Pymongo docs

中对此进行了解释
  

当插入文档时,如果文档尚未包含“_id”键,则会自动添加“_id”。 “_id”的值在整个集合中必须是唯一的。

如果要更改此行为,可以在插入前为对象指定_id属性。在我看来,这是一个坏主意。它很容易导致碰撞,你会丢失存储在“真实”ObjectId中的多汁信息,例如creation time,这对于排序和类似事情非常有用。

>>> a = {'_id': 'hello', 'key1':'value1'}
>>> collection.insert(a)
'hello'
>>> collection.find_one({'_id': 'hello'})
{u'key1': u'value1', u'_id': u'hello'}

或者,如果在序列化为Json时出现问题,您可以使用BSON模块中的utilities

>>> a = {'key1':'value1'}
>>> collection.insert(a)
ObjectId('53ad6d59867b2d0d15746b34')
>>> from bson import json_util
>>> json_util.dumps(collection.find_one({'_id': ObjectId('53ad6d59867b2d0d15746b34')}))
'{"key1": "value1", "_id": {"$oid": "53ad6d59867b2d0d15746b34"}}'

(您可以在jsonlint.com

等页面中验证这是有效的json

答案 1 :(得分:0)

显然docs回答了你的问题

MongoDB以BSON序列化格式将文档存储在磁盘上。 BSONJSON文档的二进制表示形式,但它包含的数据类型多于JSON。

字段的值可以是任何BSON数据类型,包括其他文档,数组和文档数组。以下文档包含不同类型的值:

var mydoc = {
               _id: ObjectId("5099803df3f4948bd2f98391"),
               name: { first: "Alan", last: "Turing" },
               birth: new Date('Jun 23, 1912'),
               death: new Date('Jun 07, 1954'),
               contribs: [ "Turing machine", "Turing test", "Turingery" ],
               views : NumberLong(1250000)
            }

了解有关BSON

的更多信息

答案 2 :(得分:0)

_id充当文档的主键,与SQL数据库不同,它在mongodb中是必需的。

要使_id可序列化,您有两个选项:

  1. 在插入文档之前将_id设置为文档中的JSON可序列化数据类型(例如intstr)但请记住,每个文档必须是唯一的。< / p>

  2. 使用自定义BSON序列编码器/解码器类:

    from bson.json_util import default as bson_default
    from bson.json_util import object_hook as bson_object_hook
    
    class BSONJSONEncoder(json.JSONEncoder):
        def default(self, o):
            return bson_default(o)
    
    
    class BSONJSONDecoder(json.JSONDecoder):
        def __init__(self, **kwrgs):
            JSONDecoder.__init__(self, object_hook=bson_object_hook)
    

答案 3 :(得分:0)

回答@BorrajaX的人已经想添加更多内容。 _id是唯一标识符,当将文档插入到集合中时,它会使用一些随机数生成。您可以设置自己的ID,也可以使用MongoDB为您创建的内容。

documentation对此进行了提及。

对于您的情况,您可以使用del关键字del a["_id"]来忽略此键。

如果您需要_id进行进一步的操作,则可以使用bson模块中的转储。

import json
from bson.json_util import loads as bson_loads, dumps as bson_dumps 

a["_id"]=json.loads(bson_dumps(a["_id"]))

在插入文档之前,您可以添加自定义_id,而无需序列化字典

a["_id"] = "some_id"

db1.collection1.insert(a)

答案 4 :(得分:0)

可以使用copy模块来规避此行为。这会将字典的副本传递给pymongo,而保留原样。根据您的示例中的代码片段,应按如下所示对其进行修改:

import copy
from pymongo import *
a = {'key1':'value1'}
db1.collection1.insert(copy.copy(a))
print a