How to sort mongodb with pymongo

PythonMongodbPymongo

Python Problem Overview


I'm trying to use the sort feature when querying my mongoDB, but it is failing. The same query works in the MongoDB console but not here. Code is as follows:

import pymongo

from  pymongo import Connection
connection = Connection()
db = connection.myDB
print db.posts.count()
for post in db.posts.find({}, {'entities.user_mentions.screen_name':1}).sort({u'entities.user_mentions.screen_name':1}):
    print post

The error I get is as follows:

Traceback (most recent call last):
  File "find_ow.py", line 7, in <module>
    for post in db.posts.find({}, {'entities.user_mentions.screen_name':1}).sort({'entities.user_mentions.screen_name':1},1):
  File "/Library/Python/2.6/site-packages/pymongo-2.0.1-py2.6-macosx-10.6-universal.egg/pymongo/cursor.py", line 430, in sort
  File "/Library/Python/2.6/site-packages/pymongo-2.0.1-py2.6-macosx-10.6-universal.egg/pymongo/helpers.py", line 67, in _index_document
TypeError: first item in each key pair must be a string

I found a link elsewhere that says I need to place a 'u' infront of the key if using pymongo, but that didn't work either. Anyone else get this to work or is this a bug.

Python Solutions


Solution 1 - Python

.sort(), in pymongo, takes key and direction as parameters.

So if you want to sort by, let's say, id then you should .sort("_id", 1)

For multiple fields:

.sort([("field1", pymongo.ASCENDING), ("field2", pymongo.DESCENDING)])

Solution 2 - Python

You can try this:

db.Account.find().sort("UserName")  
db.Account.find().sort("UserName",pymongo.ASCENDING)   
db.Account.find().sort("UserName",pymongo.DESCENDING)  

Solution 3 - Python

This also works:

db.Account.find().sort('UserName', -1)
db.Account.find().sort('UserName', 1)

I'm using this in my code, please comment if i'm doing something wrong here, thanks.

Solution 4 - Python

Why python uses list of tuples instead dict?

In python, you cannot guarantee that the dictionary will be interpreted in the order you declared.

So, in mongo shell you could do .sort({'field1':1,'field2':1}) and the interpreter would sort field1 at first level and field 2 at second level.

If this syntax was used in python, there is a chance of sorting by field2 at first level. With tuple, there is no such risk.

.sort([("field1",pymongo.ASCENDING), ("field2",pymongo.DESCENDING)])

Solution 5 - Python

Sort by _id descending:

collection.find(filter={"keyword": keyword}, sort=[( "_id", -1 )])

Sort by _id ascending:

collection.find(filter={"keyword": keyword}, sort=[( "_id", 1 )])

Solution 6 - Python

.sort([("field1",pymongo.ASCENDING), ("field2",pymongo.DESCENDING)])

Python uses key,direction. You can use the above way.

So in your case you can do this

for post in db.posts.find().sort('entities.user_mentions.screen_name',pymongo.ASCENDING):
        print post

Solution 7 - Python

DESC & ASC :

import pymongo

client = pymongo.MongoClient("mongodb://localhost:27017/")
db = client["mydatabase"]
col = db["customers"]

doc = col.find().sort("name", -1) #

for x in doc:
  print(x)

###################

import pymongo

client = pymongo.MongoClient("mongodb://localhost:27017/")
db = client["mydatabase"]
col = db["customers"]

doc = col.find().sort("name", 1) #

for x in doc:
  print(x)

Solution 8 - Python

TLDR: Aggregation pipeline is faster as compared to conventional .find().sort().

Now moving to the real explanation. There are two ways to perform sorting operations in MongoDB:

  1. Using .find() and .sort().
  2. Or using the aggregation pipeline.

As suggested by many .find().sort() is the simplest way to perform the sorting.

.sort([("field1",pymongo.ASCENDING), ("field2",pymongo.DESCENDING)])

However, this is a slow process compared to the aggregation pipeline.

Coming to the aggregation pipeline method. The steps to implement simple aggregation pipeline intended for sorting are:

  1. $match (optional step)
  2. $sort

NOTE: In my experience, the aggregation pipeline works a bit faster than the .find().sort() method.

Here's an example of the aggregation pipeline.

db.collection_name.aggregate([{
    "$match": {
        # your query - optional step
    }
},
{
    "$sort": {
        "field_1": pymongo.ASCENDING,
        "field_2": pymongo.DESCENDING,
        ....
    }
}])

Try this method yourself, compare the speed and let me know about this in the comments.

Edit: Do not forget to use allowDiskUse=True while sorting on multiple fields otherwise it will throw an error.

Solution 9 - Python

Say, you want to sort by 'created_on' field, then you can do like this,

.sort('{}'.format('created_on'), 1 if sort_type == 'asc' else -1)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionWildBillView Question on Stackoverflow
Solution 1 - PythonBenView Answer on Stackoverflow
Solution 2 - Pythonnew_lightView Answer on Stackoverflow
Solution 3 - PythonSnehal ParmarView Answer on Stackoverflow
Solution 4 - PythonromulomaduView Answer on Stackoverflow
Solution 5 - PythonAn SeView Answer on Stackoverflow
Solution 6 - PythonAsh UpadhyayView Answer on Stackoverflow
Solution 7 - PythonAyseView Answer on Stackoverflow
Solution 8 - PythonAnuj GuptaView Answer on Stackoverflow
Solution 9 - PythonMd. Tanvir RaihanView Answer on Stackoverflow