[英]How do you save a Python object into pymongo? (i.e. what method/return value do I need to override)
Let's say I have a class: TestClass
. 假设我有一个类:
TestClass
。 This class is slotted. 这个课程是开槽的。
class TestClass(object):
__slots__ = ('_id', 'value1', 'value2',)
So we create an object. 所以我们创建一个对象。
test = TestClass()
test.key1 = 'val1'
test.key2 = 'val2'
Great! 大! Now what I would like to do is insert
test
into a MongoDB instance. 现在我想做的是将
test
插入到MongoDB实例中。
db.test_collection.insert(test)
Uh oh. 哦,哦。
TypeError: 'TestClass' object is not iterable
Ok, let's make that iterable. 好吧,让我们把它变成可迭代的。
class TestClass(object):
__slots__ = ('_id', 'key1', 'key2',)
def __iter__(self):
yield from dict(
(slot, self.__getattribute__(slot))
for slot in self.__slots__).items()
test = TestClass()
test.key1 = 'val1'
test.key2 = 'val2'
for i in test:
print(i)
// result
// ('key1', 'val1')
// ('key2', 'val2')
db.test_collection.insert(test)
This gives me: doc['_id'] = ObjectId() // TypeError: 'tuple' object does not support item assignment
. 这给了我:
doc['_id'] = ObjectId() // TypeError: 'tuple' object does not support item assignment
。
Further, let's say I have a composition of objects... 更进一步,假设我有一个对象的组合......
test = TestClass()
test.key1 = 'val1'
test.key2 = TestClass()
Would the pymongo encoder be able to encode test.key2
when saving test
? pymongo编码器
test.key2
在保存test
时对test.key2
进行编码?
EDIT: I'm okay not saving the object directly and calling a function on the object like test.to_document()
, but the goal is to have composite fields (eg test.key2
) become a dict so that it can be saved. 编辑:我没有直接保存对象并在对象上调用函数,如
test.to_document()
,但目标是让复合字段(例如test.key2
)成为一个字典,以便保存它。
First I would ask myself, why is it important to store the object as is in the Mongodb. 首先我会问自己,为什么将对象存储在Mongodb中是很重要的。 What is it that I want to achieve here?
我想在这里实现什么?
If the answer to the above question is: "Yes, there is a valid reason for this". 如果上述问题的答案是:“是的,这是有正当理由的”。 The way to store objects is to first serialize them, and then store that serialization.
存储对象的方法是首先序列化它们,然后存储该序列化。
The pickle module does that for you. 泡菜模块为您做到了这一点。
import pickle
test = TestClass()
dumped = pickle.dumps(test)
db.objects.insert_one({"data": dumped, "name": 'test'})
It's worth noting that because these are python objects and if a user in anyway has the possibility to insert a pickled object into the database and you at some point unpickles that object it would pose a security threat to you. 值得注意的是,因为这些是python对象,并且如果用户无论如何都有可能将pickle对象插入到数据库中,并且您在某些时候对该对象进行unpickles,则会对您构成安全威胁。
As you are trying to insert an individual object rather than a series of them, the first error message you got, suggesting that PyMongo is expecting an iterable, is perhaps misleading. 当您尝试插入单个对象而不是一系列对象时,您收到的第一条错误消息,表明PyMongo期望迭代,可能会产生误导。
insert
can take either a single document (dictionary) or an iterable of them. insert
可以采用单个文档(字典)或其中的可迭代文档。
You can convert the object to a dict with a function like this : 您可以使用如下函数将对象转换为dict:
def slotted_to_dict(obj):
return {s: getattr(obj, s) for s in obj.__slots__ if hasattr(obj, s)}
Then 然后
db.test_collection.insert(slotted_to_dict(test))
should work, but is deprecated . 应该工作,但已被弃用 。 So
所以
db.test_collection.insert_one(slotted_to_dict(test))
is probably better. 可能更好。
Note that if you are frequently converting the slotted object to a dict, then you might be losing any performance benefit from using slots. 请注意,如果您经常将插槽对象转换为dict,那么使用插槽可能会失去任何性能优势。 Also, the "_id" attribute will not be set in the test object, and you might need an awkward solution like this to save the ID:
此外,“_id”属性不会在测试对象中设置,您可能需要这样一个尴尬的解决方案来保存ID:
test._id = db.test_collection.insert_one(slotted_to_dict(test))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.