You seek 2 different $group at the same time -- this is exactly what $facet is for. Think of $facet like "multi-group." Given an input set similar to the following:
{ religion: 'a', province: 'aa' }, { religion: 'b', province: 'aa' }, { religion: 'c', province: 'aa' }, { religion: 'c', province: 'bb' }, { religion: 'd', province: 'bb' }, { religion: 'e', province: 'cc' }, { religion: 'f', province: 'aa' }, { religion: 'f', province: 'aa' }, { religion: 'f', province: 'aa' }, { religion: 'f', province: 'cc' }
Then this pipeline:
db.foo.aggregate([ {$facet: { "by_religion": [ {$group: {_id: '$religion', N:{$sum:1}}} ], "by_province": [ {$group: {_id: '$province', N:{$sum:1}}} ], }} ]);
yields this output:
{ "by_religion" : [ { "_id" : "b", "N" : 1 }, { "_id" : "e", "N" : 1 }, { "_id" : "d", "N" : 1 }, { "_id" : "a", "N" : 1 }, { "_id" : "f", "N" : 4 }, { "_id" : "c", "N" : 2 } ], "by_province" : [ { "_id" : "bb", "N" : 2 }, { "_id" : "cc", "N" : 2 }, { "_id" : "aa", "N" : 6 } ] }
The OP seeks to further refine the output by doing some data-as-LVAL workup and although this is in general considered a poor design practice, it has certain useful applications. Add this stage after $facet:
,{$project: { // Reading this from insider-out: // We use $map to turn the array of objects: // [ {_id:'d',N:1},{_id:'f',N:4}, ... ] // into an array of K-v pairs (array of array): // [ ['d',1] , ['f',4] , ... ] // That sets us up for $arrayToObject which will take // that array of arrays and turn it into an object: // {'d':1, 'f':4, ... } // The target field name is the same as the input so // we are simply overwriting the field. "by_religion": {$arrayToObject: {$map: { input: '$by_religion', in: [ '$$this._id', '$$this.N' ] }} }, "by_province": {$arrayToObject: {$map: { input: '$by_province', in: [ '$$this._id', '$$this.N' ] }} } }}
to yield:
{ "by_religion" : { "d" : 1, "b" : 1, "c" : 2, "f" : 4, "a" : 1, "e" : 1 }, "by_province" : { "bb" : 2, "cc" : 2, "aa" : 6 } }
A variation on the lval/rval workup uses this $project instead of the one immediately above:
,{$project: { "by_religion": {$map: { input: '$by_religion', in: {$arrayToObject: [ [{k:'$$this._id',v:'$$this.N'}] ]} }}, "by_province": {$map: { input: '$by_province', in: {$arrayToObject: [ [{k:'$$this._id',v:'$$this.N'}] ]} }}, }}
which yields an array:
{ "by_religion" : [ {"b" : 1}, {"c" : 2}, {"a" : 1}, {"f" : 4}, {"d" : 1}, {"e" : 1} ], "by_province" : [ {"cc" : 2}, {"aa" : 6}, {"bb" : 2} ] }