129

With PyMongo, when I try to retrieve objects sorted by their 'number' and 'date' fields like this:

db.test.find({"number": {"$gt": 1}}).sort({"number": 1, "date": -1})

I get this error:

TypeError: if no direction is specified, key_or_list must be an instance of list

What's wrong with my sort query?

Armut
  • 969
  • 8
  • 22
KennyPowers
  • 4,925
  • 8
  • 36
  • 51

1 Answers1

235

sort should be a list of key-direction pairs, that is

db.test.find({"number": {"$gt": 1}}).sort([("number", 1), ("date", -1)])

The reason why this has to be a list is that the ordering of the arguments matters and dicts are not ordered in Python < 3.6

georg
  • 211,518
  • 52
  • 313
  • 390
  • 33
    The reason that this is a list in Python is that the ordering of the arguments to `sort()` matters and dicts are not ordered in Python. – André Laszlo Nov 16 '12 at 12:11
  • @AndréLaszlo can an OrderedDict() be used? – zakdances Mar 12 '13 at 23:16
  • @yourfriendzak, I'm afraid not. It's a bit unpythonic, I guess. [Here's the reason why](http://api.mongodb.org/python/1.0/pymongo-pysrc.html#L70), at line 70. An OrderedDict is not an instance of types.ListType. – André Laszlo Mar 14 '13 at 12:02
  • 9
    This saved me a ton of research. The Little MongoDB Book misleads in sort examples. – Dogukan Tufekci Apr 20 '13 at 22:22
  • 6
    If it is only one field, it can be .sort("_id", 1) – Cyber Square Professional Mar 15 '18 at 11:51
  • Kinda a bummer that mongodb's documentation examples use dictionaries instead of list of tuples, but it makes sense why pymongo needs them. JSONs are ordered dictionaries (as strings) -- pymong's error message could be clearer on what to change to solve the problem. – Marc Maxmeister May 08 '18 at 19:46
  • 2
    in python3.6+ dicts are ordered so if anyone is up for it, might be worth a pull request to pymongo to bring it in line with generic mongodb syntax. Of course this wouldn't work when running pymongo on older python versions.. – thiezn May 08 '18 at 21:41
  • if you want to sort a single field, this is another way .sort('{}'.format('created_on'), 1 if sort_type == 'asc' else -1) – Md. Tanvir Raihan Apr 29 '20 at 05:17