Ethan Turkeltaub
Ethan Turkeltaub

Reputation: 2961

Group then Sort with MongoDB

I'm trying to count the number of documents associated with an ID, then sort the results. Here's an example document (in the media collection).

{
  "_id" : "00wlz2j2cu9kx",
  "uploadedBy" : { 
    "uid" : "00wen1b4tfwn6",
  }
}

Basically, I need to group all of these documents by uploadedBy.uid, sort by the resulting array by a count of documents. I have this command thus far:

db.media.group({
  key: {
    'uploadedBy.uid' : true
  },

  reduce: function(obj, prev) {
    prev.total += 1
  },

  initial: {
    total: 0
  }
})

Which gives me this array as a result.

[
  {
    "uploadedBy.uid" : "00wen1b4tfwn6",
    "total" : 1
  },
  {
    "uploadedBy.uid" : "00wp0s9c73dvl",
    "total" : 2
  }
]

Now I just need to sort each of these documents by the total field. How do I do this?

Upvotes: 2

Views: 2173

Answers (2)

dyrkin
dyrkin

Reputation: 544

In case if node.js support aggregation framework try to use it

db.media.aggregate([
    {$group: {_id: '$uploadedBy.uid', 'count': {$sum: 1}}},
    {'$sort': {'count': -1}}
])

I'm not sure that this code have no issues, but you can try something like this.

EDIT Changed the query to work properly. This answer worked for me. You can also add skip/limit here to get top 5 results, as illustrated below:

db.media.aggregate([
    {$group: {_id: '$uploadedBy.uid', 'count': {$sum: 1}}},
    {'$sort': {'count': -1}},
    {'$skip': 0},
    {'$limit': 5}
])

Upvotes: 2

Robert Mitchell
Robert Mitchell

Reputation: 1334

I would recommend using the Aggregation Framework for this, if your MongoDB version >= 2.1. Many simple aggregation queries are easier to write with it as opposed to MapReduce (the group() function you are using currently uses MapReduce under the covers).

The aggregation framework provides an easy $sort option to order your results, as follows:

var MongoClient = require("mongodb").MongoClient;

MongoClient.connect("mongodb://localhost/myDb", function (err, db) {
    "use strict";
    var collection = db.collection("media"),
        resultsHandler = function (err, results) {
            if (err) {
                console.log(err);
            }
            console.log(results);
        };

    collection.aggregate(
        {
            $group: {
                _id: { uid: "$uploadedBy.uid" },
                total: { $sum: 1 }
            }
        },
        {
            $sort: {
                total: -1
            }
        },
        resultsHandler
    );
});

Upvotes: 3

Related Questions