How to get ordered dictionaries in pymongo?

∥☆過路亽.° 提交于 2019-12-28 02:10:45

问题


I am trying get ordered dictionaries in Pymongo. I have read it can be done with bson.son.Son. The Docs are Here

However, I can't seem to make it work. There is not much on google about it. There are some discussions on configuring pymongo first to tell it to use SON objects but no examples. A friend suggested passing a param when you do a find. He couldn't remember.

I'm able to create the SON objects. But when they get inserted into the DB and then come back out they are just plain dicts.

I'm not sure really what code example to give you because I really don't know where to start. The below snippet creates an empty SON object every time I add a new user. The 'sub_users' object was also created with SON. When I read the account document back from the DB they are just normal python dicts.

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

Maybe a param past to the find like this to configure? This was my friends suggestion but he could not remember.

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

Any ideas?


回答1:


You can use bson.son.SON or OrderedDict to store ordered dict.

And retrive data with as_class=OrderedDict option.

Here is an example:

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)))

Output:

[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)])]



回答2:


This solution above is correct for older versions of MongoDB and the pymongo driver but it no longer works with pymongo3 and MongoDB3+ You now need to add document_class=OrderedDict to the MongoClient constructor. Modifying the above answer for pymongo3 compatibility.

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})))

Output:

[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)])]



回答3:


A standard find() in PyMongo will not return an object who's fields are in the same order as that object, if you retrieved it via mongo shell.

This is because, the default type returned is a Dict and the order is not defined.

You can use SON as suggested. Here is how I did it. Now the field order will be respected.

This is for 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'})



回答4:


In PyMongo v3.2 insert() has been deprecated and in this example it should be replaced with insert_one(). Updated code is below:

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})))

Output:

[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)])]


来源:https://stackoverflow.com/questions/23001156/how-to-get-ordered-dictionaries-in-pymongo

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!