我在某处读到,您可以使用 BSON 将 python 对象(更具体地说是字典)作为二进制文件存储在 MongoDB 中。但是现在我找不到任何与此相关的文档。
有人知道这到底是如何做到的吗?
没有办法在不序列化的情况下将对象存储在文件(数据库)中。如果数据需要从一个进程移动到另一个进程或另一台服务器,则需要以某种形式序列化才能传输。既然您询问的是 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)})
假设您对 mongoDB 不是特别感兴趣,您可能不会寻找 BSON。与 JSON 相比,BSON 只是一种不同的序列化格式,旨在提高速度和空间效率。另一方面,
pickle
更多的是对Python对象进行直接编码。
但是,在采用
pickle
之前请先进行速度测试,以确保它更适合您的用例。
看来您仍然需要使用
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
要将 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)