如何在pymongo中获取有序字典?

18

我正在尝试在Pymongo中获取有序字典。据我所知,可以使用bson.son.Son实现。文档在这里

然而,我似乎无法使其正常工作。谷歌上关于此的信息不多。有一些讨论要先配置pymongo以告诉它使用SON对象,但没有示例。一个朋友建议在find时传递参数,但他记不起来了。

我能够创建SON对象。但当它们被插入数据库,再取出时,它们只是普通的字典。

我真的不知道从哪里开始,也不确定应该给你什么代码示例。下面的片段每次添加新用户时都会创建一个空的SON对象。'sub_users'对象也是用SON创建的。但当我从数据库中读取帐户文档时,它们只是普通的Python字典。

    account['sub_users'][sub_user_name] = bson.SON()
    with mongo_manager.Collection(CFG.db, 'Users') as users:
        users.save(account)

或许可以通过像这样的参数传递给 find 来进行配置?这是我的朋友建议的,但他记不清了。

with mongo_manager.Collection(CFG.db, 'Users') as users:                                 
    account = users.find_one({'_id': _id, 'DOC':'OrderedDict})

有什么想法吗?

4个回答

20

对于较旧版本的MongoDB和pymongo驱动程序,上述解决方案是正确的,但在pymongo3和MongoDB3+中不再适用。现在,您需要在MongoClient构造函数中添加document_class=OrderedDict。 修改上面的答案以适应pymongo3兼容性。

from collections import OrderedDict
from pymongo import MongoClient
import bson

client = MongoClient(document_class=OrderedDict)
sample_db = client['sample']
test_col = sample_db['test']

test_col.drop()

data = OrderedDict([("one", 1), ("two", 2), ("three", 3), ("four", 4)])
test_col.insert(data)
print(list(test_col.find({}, {'_id': 0})))

test_col.drop()

data = bson.son.SON([("one", 1), ("two", 2), ("three", 3), ("four", 4)])
test_col.insert(data)
print(list(test_col.find({}, {'_id': 0})))

输出:

[OrderedDict([(u'one', 1), (u'two', 2), (u'three', 3), (u'four', 4)])]
[OrderedDict([(u'one', 1), (u'two', 2), (u'three', 3), (u'four', 4)])]

14

你可以使用bson.son.SON或者OrderedDict来存储有序字典。

并且使用as_class=OrderedDict选项来检索数据。

这里是一个示例:

from collections import OrderedDict
from pymongo import MongoClient
import bson

client = MongoClient()
sample_db = client['sample']
test_col = sample_db['test']

test_col.drop()

data = OrderedDict([("one", 1), ("two", 2), ("three", 3), ("four", 4)])
test_col.insert(data)
print(list(test_col.find({}, {'_id': 0}, as_class=OrderedDict)))

test_col.drop()

data = bson.son.SON([("one", 1), ("two", 2), ("three", 3), ("four", 4)])
test_col.insert(data)
print(list(test_col.find({}, {'_id': 0}, as_class=OrderedDict)))

输出:

[OrderedDict([(u'one', 1), (u'two', 2), (u'three', 3), (u'four', 4)])]
[OrderedDict([(u'one', 1), (u'two', 2), (u'three', 3), (u'four', 4)])]

1
使用OrderedDictSON对象是否会影响性能?从源代码来看(这里这里),两者都是dict的子类,但是OrderedDict有一个C实现(并带有一个纯Python实现作为后备),而SON似乎只有一个Python实现... - Gustavo Bezerra
我遇到了一个错误 - "init() got an unexpected keyword argument 'as_class'". - Kalyanam Rajashree
@KalyanamRajashree 这是因为它已被删除 - Guy

4

在PyMongo中,标准的find()不会返回一个与通过mongo shell检索到的对象字段顺序相同的对象,因为默认返回的类型是字典,其顺序未定义。

建议使用SON。以下是我的做法。现在将尊重字段顺序。

这适用于pymongo == 3.4.0

from bson.codec_options import CodecOptions
from bson.son import SON

opts = CodecOptions(document_class=SON)
collection_son = mongo.db.collection.with_options(codec_options=opts)

collection_son.find_one({"imsid": '12345'})

3

在 PyMongo v3.2 中,insert() 已经被弃用,在这个例子中需要用 insert_one() 替换。更新后的代码如下:

from collections import OrderedDict
from pymongo import MongoClient
import bson

client = MongoClient(document_class=OrderedDict)
sample_db = client['sample']
test_col = sample_db['test']

test_col.drop()

data = OrderedDict([("one", 1), ("two", 2), ("three", 3), ("four", 4)])
test_col.insert_one(data)
print(list(test_col.find({}, {'_id': 0})))

test_col.drop()

data = bson.son.SON([("one", 1), ("two", 2), ("three", 3), ("four", 4)])
test_col.insert_one(data)
print(list(test_col.find({}, {'_id': 0})))

输出:

[OrderedDict([(u'one', 1), (u'two', 2), (u'three', 3), (u'four', 4)])]
[OrderedDict([(u'one', 1), (u'two', 2), (u'three', 3), (u'four', 4)])]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接