Aggregate function and Count

In this post, I’ll explain how to add total of your record set to your element using Aggregate function. So, I wanted to print the subjects list with the total of documents that are stored into them.

mongoDB_aggregate_count

To do this, I worked first in MongoDB to get the results that I wanted. And I got them! (after many tries). You can find moreĀ Aggregation examples.

MongoDB Shell

> db.documents.group({
...     key: {subject:1 }
...     ,cond: {}
...     ,reduce: function(curr, result){
...         result.count++;
...     }
...     ,initial: {count:0}
... });
[
        {
                "subject" : "dogs",
                "count" : 3
        },
        {
                "subject" : "databases",
                "count" : 3
        },
        {
                "subject" : "cosmos",
                "count" : 3
        },
        {
                "subject" : "health",
                "count" : 3
        }
]
>
 

But translating this code into Mongoose syntax was quite a challenge. But after reading details about Aggregate function I could implement it into ourĀ code.

Mongoose syntax in Documents route

...
// count
router.get('/count', function(req, res){
	// Start timing now
	console.time('documents.router.get.count.job.timespan');

	//get all documents on collection
	documents.aggregate([
		{
			$group : {
				_id : '$subject'
				,count : { $sum : 1 }
			}
		}
		,{
			$sort : {
				_id : 1
			}
		}]
		,function(err, docs){
			if(err) res.json(err);
			else {
				// return results
				res.json(docs);

				// log
				console.log('documents.router.get.count');
				console.log('query: '+ JSON.stringify(req.query));
				console.log('params: '+ JSON.stringify(req.params));

				// Stop timer.
				console.timeEnd('documents.router.get.count.job.timespan');
				console.log('\n');
			}
	});
});
...
 

The above code returns this JSON data when we call the server http://localhost:3000/documents/count. It is composed by objects formed by two elements: “_id” and “count”, where “_id” is the subject name. We could also do a sort on “_id” in order to get subjects order alphabetically.

[{"_id":"cosmos","count":3},{"_id":"databases","count":3},{"_id":"dogs","count":3},{"_id":"health","count":3}]
 

This data is consumed by the Client setting the subjectsCountList scope variable in the AngularJS controller that uses the DocumentsCount services:

angular.module('myLibraryApp.services', [])
	.factory('Subjects', function( $resource ) {
		return $resource('http://localhost:3000/subjects/:id', { id : '@_id' }, {
			'update' : { method : 'PUT' }
		});
	})
	.factory('Documents', function( $resource ) {
		return $resource('http://localhost:3000/documents/:id', { id : '@_id' }, {
			'query' : { method : 'GET', params : { subject : '@subject' }, isArray : true },
			'update' : { method : 'PUT' }
		});
	})
	.factory('DocumentsCount', function( $resource ) {
		return $resource('http://localhost:3000/documents/count');
	});
 
angular.module('myLibraryApp')
	.controller('SubjectsListController', function ($scope, $state, Subjects, DocumentsCount) {
	...
		// documents count by subject
		$scope.subjectsCountList = DocumentsCount.query();
	...
 

Finally we populate the data into our HTML code using AngularJS

<h3>Navigate by subject</h3>
<ul class="nav nav-pills" role="tablist">
	<li ng-repeat="subject in subjectsCountList" role="presentation">
		<a ui-sref="documents.subject ({ subject : subject._id }) ">
			{{ subject._id }} <span class="badge">{{ subject.count }}</span>
		</a>
	</li>
</ul>
 

Related Links

http://mongoosejs.com/docs/api.html#model_Model.aggregate

http://docs.mongodb.org/manual/applications/aggregation/

http://docs.mongodb.org/manual/reference/method/db.collection.aggregate/

http://en.wikipedia.org/wiki/Aggregate_function

1 thought on “Aggregate function and Count

Leave a comment