How can I translate the following Sql
query for Mongo
?:
select a,b,sum(c) csum from coll wh
I want to add the following query, as an example, it may be useful in case of two groupings.
Query:
db.getCollection('orders').aggregate([
{$match:{
tipo: {$regex:"[A-Z]+"}
}
},
{$group:
{
_id:{
codigo:"1",
fechaAlta:{$substr:["$fechaAlta",0,10]},
},
total:{$sum:1}
}
},
{$sort:
{"_id":1}
},
{$group:
{
_id:"$_id.codigo",
fechasAltas:
{
$push:
{
fechaAlta:"$_id.fechaAlta",
total:"$total"
}
},
totalGeneral:{$sum:"$total"}
}
}
]);
Response:
{
"_id" : "1",
"fechasAltas" : [
{
"fechaAlta" : "1940-01-01",
"total" : 13.0
},
{
"fechaAlta" : "2007-05-14",
"total" : 115.0
},
{
"fechaAlta" : "2008-09-30",
"total" : 58.0
},
.
.
.
],
"totalGeneral" : 50620.0
}
Inspired by this example on mongo's website.
GENERATE DUMMY DATA:
> db.stack.insert({a:1,b:1,c:1,active:1})
> db.stack.insert({a:1,b:1,c:2,active:0})
> db.stack.insert({a:1,b:2,c:3,active:1})
> db.stack.insert({a:1,b:2,c:2,active:0})
> db.stack.insert({a:2,b:1,c:3,active:1})
> db.stack.insert({a:2,b:1,c:10,active:1})
> db.stack.insert({a:2,b:2,c:10,active:0})
> db.stack.insert({a:2,b:2,c:5,active:1})
MONGO QUERY:
> db.stack.aggregate(
... {$match:{active:1}},
... {$group:{_id:{a:"$a", b:"$b"}, csum:{$sum:"$c"}}},
... {$sort:{"_id.a":1}})
RESULT:
{"result" : [
{"_id" : {"a" : 1,"b" : 2},"csum" : 3},
{"_id" : {"a" : 1,"b" : 1},"csum" : 1},
{"_id" : {"a" : 2,"b" : 2},"csum" : 5},
{"_id" : {"a" : 2,"b" : 1},"csum" : 13}
],"ok" : 1}
(NOTE: I reformatted the shell result a bit so it is more readable)
The mongodb aggregation API seems to have changed. Now you would do
db.coll.aggregate([
{
$group: {
_id: "$a",
countA: { $sum: 1},
sumC:{ $sum: "$c"},
}
},
{
$sort:{a:1}
}
])
Note the Array syntax for the argument to aggregate(). You'd also add things link $match, $limit etc. as elements of this array.
Adding to previous answers, if you want to sort on the sum (the result of the aggregate) instead of on the actual column, you can do this:
db.your_collection.aggregate([
{
$group: {_id: "$your_document_name", count: {$sum: 1}}
},
{
$sort: {"count":-1}
}
])
This would be the equivalent of the following standard-SQL-ish syntax:
select col_a, count(col_a) as b
from table
group by col_a
order by b desc
Until the Aggregation Framework is release in MongoDB 2.1, the call for group as in this answer, is rather slow, since it is using the JavaScript part of the DB.
You can use a faster approach for counting groups:
var res = [];
for( var cur_a = db.coll.distinct('a'); cur_a.hasNext(); ) {
var a = cur_a.next();
for( var cur_b = db.coll.distinct('b'); cur_b.hasNext(); ) {
var b = cur_b.next();
res.push({ 'a': a, 'b' : b 'count': db.coll.count({'a':a,'b':b})}
}
}
It will be faster if you have indexes on a and b
db.coll.ensureIndex({'a':1,'b':1})
Using the aggregate framework, you can do the following:
db.coll.aggregate({
$group: {
_id: "$a",
countA: { $sum: 1},
sumC:{ $sum: "$c"},
},
$sort:{a:1}
});
However, if you have too much data you may get the following error message:
{
"errmsg" : "exception: aggregation result exceeds maximum document size (16MB)",
"code" : 16389,
"ok" : 0
}
See more about SQL to Mongo translation here: http://docs.mongodb.org/manual/reference/sql-aggregation-comparison/