How to get ordered dictionaries in pymongo?

fat fantasma picture fat fantasma · Apr 11, 2014 · Viewed 8.3k times · Source

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?

Answer

Alan Viars picture Alan Viars · Jun 11, 2015

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