Question

I am doing some aggregation on a mongo 2.4.9 collection but I am not able to sort the result by two fields. Here is the query I am making using PyMongo:

result = mongo_coll.aggregate([{"$match": {"_cls": "class1"},
                               {"$group": {"_id": {"currency": "$total.currency",
                                                   "v_id": "$v_id"},
                                           "total": {"$sum": "$total.amount"},
                                           "count": {"$sum": 1}}},
                               {"$sort": {"_id.currency": 1, "total": -1}}])

And I have the result sorted by "total":-1

If I replace the last line with the following:

                               {"$sort": {"total": -1, "_id.currency": 1}}])

It is still sorted by "total":-1

And if I replace it with the following:

                               {"$sort": {"_id.currency": 1}}])

It gets sorted by currency.

But I can't get it sorted how I want, which means by currency first, and then by total... (The results else look good, as expected). Anybody has a clue ?

Best and thanks in advance !

UPDATE: Here is a sample doc:

{
  "_id": { "$oid" : "533d0a3b830f783478a75aa1" },
  "_cls": "class1",
  "v_id": 6813,
  "total": {
    "amount": 680,
    "currency": "EUR",
    "exp": -2
  }
}
Was it helpful?

Solution

I could actually find the reason why this is happening with Python thanks to the answer of Bernie in the MongoDB User Google Group:

Python dict are unordered and this is pretty sensible for doing ordering :-p

This is why the parameter could be given as a BSON.SON dict or as an OrderedDict to keep it more pythonic !

Here is the solution I used :

    from collections import OrderedDict
    sort_dict = OrderedDict()
    sort_dict['_id.currency'] = 1
    sort_dict['total'] = -1

And then

{"$sort": sort_dict}

EDIT The link from response in google user group...

OTHER TIPS

If you want the sorting to happen by Currency first, then you should change your sort to - {"$sort": {"_id.currency": 1, "total": -1}}. The sorting order is driven by the order in which you specify the keys.

These are the sample documents that I created -

{ "_id" : ObjectId("533dc9d272337e43d14600f7"), "_cls" : "class1", "v_id" : 6813, "total" : { "amount" : 680, "currency" : "EUR", "exp" : -2 } }
{ "_id" : ObjectId("533dc9d972337e43d14600f8"), "_cls" : "class1", "v_id" : 6813, "total" : { "amount" : 690, "currency" : "EUR", "exp" : -2 } }
{ "_id" : ObjectId("533dc9de72337e43d14600f9"), "_cls" : "class1", "v_id" : 6813, "total" : { "amount" : 690, "currency" : "USD", "exp" : -2 } }
{ "_id" : ObjectId("533dc9e672337e43d14600fa"), "_cls" : "class1", "v_id" : 6813, "total" : { "amount" : 680, "currency" : "USD", "exp" : -2 } }
{ "_id" : ObjectId("533dcd0172337e43d14600fb"), "_cls" : "class1", "v_id" : 6813, "total" : { "amount" : 2000, "currency" : "CHE", "exp" : -2 } }
{ "_id" : ObjectId("533dcdfb72337e43d14600fc"), "_cls" : "class1", "v_id" : 6814, "total" : { "amount" : 2000, "currency" : "CHE", "exp" : -2 } }
{ "_id" : ObjectId("533dce1572337e43d14600fd"), "_cls" : "class1", "v_id" : 6815, "total" : { "amount" : 1000, "currency" : "CHE", "exp" : -2 } }

for query - db.sample4.aggregate([{"$match": {"_cls": "class1"}},{$group:{"_id":{"currency":"$total.currency","v_id":"$v_id"},"total":{$sum:"$total.amount"}}},{"$sort": {"_id.currency": 1, "total": -1}}]) output is -

{
    "result" : [
        {
            "_id" : {
                "currency" : "CHE",
                "v_id" : 6814
            },
            "total" : 2000
        },
        {
            "_id" : {
                "currency" : "CHE",
                "v_id" : 6813
            },
            "total" : 2000
        },
        {
            "_id" : {
                "currency" : "CHE",
                "v_id" : 6815
            },
            "total" : 1000
        },
        {
            "_id" : {
                "currency" : "EUR",
                "v_id" : 6813
            },
            "total" : 1370
        },
        {
            "_id" : {
                "currency" : "USD",
                "v_id" : 6813
            },
            "total" : 1370
        }
    ],
    "ok" : 1
}

for query db.sample4.aggregate([{"$match": {"_cls": "class1"}},{$group:{"_id":{"currency":"$total.currency","v_id":"$v_id"},"total":{$sum:"$total.amount"}}},{"$sort": {"_id.currency": 1, "total": 1}}]) output is -

{
    "result" : [
        {
            "_id" : {
                "currency" : "CHE",
                "v_id" : 6815
            },
            "total" : 1000
        },
        {
            "_id" : {
                "currency" : "CHE",
                "v_id" : 6814
            },
            "total" : 2000
        },
        {
            "_id" : {
                "currency" : "CHE",
                "v_id" : 6813
            },
            "total" : 2000
        },
        {
            "_id" : {
                "currency" : "EUR",
                "v_id" : 6813
            },
            "total" : 1370
        },
        {
            "_id" : {
                "currency" : "USD",
                "v_id" : 6813
            },
            "total" : 1370
        }
    ],
    "ok" : 1
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top