有没有一种方法可以将python对象直接存储在mongoDB中而不需要序列化它们

问题描述 投票:0回答:4

我在某处读到,您可以使用 BSON 将 python 对象(更具体地说是字典)作为二进制文件存储在 MongoDB 中。但是现在我找不到任何与此相关的文档。

有人知道这到底是如何做到的吗?

python mongodb pymongo bson
4个回答
42
投票

没有办法在不序列化的情况下将对象存储在文件(数据库)中。如果数据需要从一个进程移动到另一个进程或另一台服务器,则需要以某种形式序列化才能传输。既然您询问的是 MongoDB,那么数据绝对会以某种形式序列化,以便存储在 MongoDB 数据库中。使用 MongoDB 时,它是BSON

如果您实际上是在询问是否有一种方法可以在 MongoDB 文档中存储更原始形式的 Python 对象,您可以将

Binary
字段插入到文档中,该文档可以包含您想要的任何数据。它无法以这种形式以任何方式直接查询,因此您可能会失去使用 MongoDB 等 NoSQL 文档数据库的很多好处。

>>> from pymongo import MongoClient
>>> client = MongoClient('localhost', 27017)
>>> db = client['test-database']
>>> coll = db.test_collection    
>>> # the collection is ready now 
>>> from bson.binary import Binary
>>> import pickle
>>> # create a sample object
>>> myObj = {}
>>> myObj['demo'] = 'Some demo data'
>>> # convert it to the raw bytes
>>> thebytes = pickle.dumps(myObj)
>>> coll.insert({'bin-data': Binary(thebytes)})

5
投票

假设您对 mongoDB 不是特别感兴趣,您可能不会寻找 BSON。与 JSON 相比,BSON 只是一种不同的序列化格式,旨在提高速度和空间效率。另一方面,

pickle
更多的是对Python对象进行直接编码。

但是,在采用

pickle
之前请先进行速度测试,以确保它更适合您的用例。


0
投票

看来您仍然需要使用

pickle
模块进行序列化,该模块会创建字节,并使用
pickle
反序列化这些字节将直接提供 python 对象。

此外,您还可以将

pickled
对象直接存储到 Mongo 中。

import pickle as pkl
from uuid import uuid4

from pymongo import MongoClient

data = dict(key='mongo')
picked_data = pkl.dumps(data)
uid = uuid4()

client = MongoClient() # add DB url in the constructor if needed
db = client.test

# insertion
db.data.insert_one({
    'uuid': uid,
    'data': picked_data
})

# retrieval
result = db.data.find_one({'uuid': uid})
assert pkl.loads(result['data']) == data

0
投票

要将 MongoDB 文档转换为 Pydantic 对象:

@classmethod
def new_from_document(cls, document):  
   # determine the target class into which the Mongo document must be converted:
   classname = cls.__name__ 

   # determine the module in which the target class resides: 
   modulename = classname.lower()

   # import the actual module by the module name that we reasoned:
   module = importlib.import_module(modulename)

   # get a reference to the class object of the target class inside the module:
   class_ref = getattr(module, classname)

   # since our Pydantic objects are expected to have "id" field
   # whereas MongoDB document has an "_id" field
   # make a clone of the document that has "id" field:  
   document_with_id = {**document, "id": document["_id"]}

   # finally, create an instance of target class passing the document as constructor parameter:
   return class_ref(**document_with_id)

请参阅完整示例:https://www.metamatic.net/python/pydantic/mongodb/2023/09/09/how-to-store-pydantic-soccer-players-in-the-mongo-database.html

© www.soinside.com 2019 - 2024. All rights reserved.