简体   繁体   English

你如何将Python对象保存到pymongo? (即我需要覆盖什么方法/返回值)

[英]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.

相关问题 (Python3)如何获取python中远程文件的时间戳(即Web链接)? - (Python3) How do you get the time stamp of a remote file in python (i.e. a web link)? 如何在 python 中返回一个元组元组? 即 ((((1, 8), (4, 5)), ((2, 7), (3, 6))),) 它一直返回 None - How do I return a tuple of tuples in python? i.e. ((((1, 8), (4, 5)), ((2, 7), (3, 6))),) It keeps returning None 如何删除列表中的特定附加字典(即其键和值) - How do you delete a specific appended dictionary (i.e. its key and value) in a list 你如何在 Python Pandas 中分组、排序和限制? (即获得前 10 名) - How do you group, sort, and limit in Python Pandas? (i.e. Get Top 10) 如何比较两个列表并返回差值? (python中的差异函数不会返回我需要的东西) - How do you compare 2 lists and return the difference? (difference function in python does not return what I need) 这个错误代码告诉我什么? 即我需要修复什么 - What is this error code telling me? i.e. what do I need to fix 如何覆盖python对象中的__type__方法? - How do I override __type__ method in python object? 我需要重写什么方法才能使列表子项返回内部数据数组而不是自身? - What method do I need to override for list child to return internal data array instead of itself? Python 如何用实际值替换 openapi json 引用,即 $ref = '#/hey/wtf/~1something~1nothing/yeah' - Python How do you replace a openapi json reference with the actual value i.e. $ref = '#/hey/wtf/~1something~1nothing/yeah' 如何覆盖 Python 中的装饰方法? - How do I override a decorated method in Python?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM