MongoDB aggregation allows developers to perform complex operations while working with data stored inside a collection of a MongoDB database.
One of the operations is the “group by” operation, i.e. $group, which is used to group documents based on the value of the field specified and count the number of documents in each group
In this article, we will learn about the “Group By” operation, how to use the MongoDB aggregate $group, select a field by group, and apply an aggregation pipeline to count the total count in each group.
Also Read: MongoDB Aggregation $sort
MongoDB Aggregate $group Stage
The MongoDB aggregate $group function is used to group the documents in the collection by the specified field. It can be used to perform various operations on grouped data using accumulator operators such as $sum, $avg, $max, $min, etc.
Our main focus is on the $sum operator which we will use to calculate the total number in each group.
Syntax:
{ $group: {
_id: <expression>,
<field>: { <accumulator> : <expression> }
} }
- _id: The name of the field to group documents,
- <field>: This is an optional argument, which is the field’s name to show in the returned documents,
- <accumulator>: The name of the accumulator operator to use,
- <expression>: The expression specifies the input to the accumulator operator.
Performing the Group By operation with Count in MongoDB
As we’ve already mentioned, the $group function can take accumulator operators such as $sum, $avg, $max, $min, $push, and $addToSet. To select the count we have to use the $sum operator among them.
Syntax:
{ $group: {
_id: <expression>,
<field>: { $sum : 1 }
} }
Here we have passed 1 to the $sum operator because we want that for each document that has a unique value for the specified field, the $sum operator adds 1 to the counter so that at the end we get the total count for each grouped document.
Examples of Counting Documents Using the Aggregate $group Stage
To demonstrate various examples, we have the below sample document inserted in a collection “drones”, take a look at them to see the difference between the return document.
Below are the documents inside the “drones” collection:
> db.drones.find().pretty()
{
"_id" : ObjectId("61673f46b34f185eb7b2bf0c"),
"onSale" : false,
"name" : "Nimbari Gryphon Medeta 65",
"price" : 77500,
"weight" : "77 kilograms",
"additionalDetails" : {
"material" : "carbon fiber",
"moreUses" : [
"Precision Agriculture",
"Land Inspection",
"Water Inspection",
"Cinematography"
]
},
"utility" : [
"Recreation",
"Photography",
"Videography",
"Delivery",
"Natural Resource Exploration"
]
}
{
"_id" : ObjectId("61673f46b34f185eb7b2bf0d"),
"onSale" : false,
"name" : "X-Strimmer Eye",
"price" : 23500,
"weight" : "24 kilograms",
"additionalDetails" : {
"material" : "glass fiber",
"moreUses" : [
"Precision Agriculture",
"Cinematography"
]
},
"utility" : [
"Recreation",
"Photography",
"Videography",
"Delivery",
"Natural Resource Exploration"
]
}
{
"_id" : ObjectId("61673f46b34f185eb7b2bf0e"),
"onSale" : false,
"name" : "Khai Balemosh Shefqa TRX",
"price" : 120500,
"weight" : "80 kilograms",
"additionalDetails" : {
"material" : "aluminum",
"moreUses" : [
"Precision Agriculture",
"Land Inspection"
]
},
"utility" : [
"Recreation",
"Photography",
"Videography",
"Delivery",
"Natural Resource Exploration"
]
}
{
"_id" : ObjectId("61673f46b34f185eb7b2bf0f"),
"onSale" : false,
"name" : "Sifinist Croma AX",
"price" : 99500,
"weight" : "97 kilograms",
"additionalDetails" : {
"material" : "lithium",
"moreUses" : [
"Precision Agriculture",
"Land Inspection",
"Water Inspection",
"Videography"
]
},
"utility" : [
"Recreation",
"Photography",
"Videography",
"Delivery",
"Natural Resource Exploration"
]
}
{
"_id" : ObjectId("61673f46b34f185eb7b2bf10"),
"onSale" : false,
"name" : "Drovce Finnifield FR-7",
"price" : 87600,
"weight" : "13 kilograms",
"additionalDetails" : {
"material" : "polysterene",
"moreUses" : [
"Precision Agriculture",
"Land Inspection",
"Water Inspection",
"Videography"
]
},
"utility" : [
"Recreation",
"Photography",
"Videography",
"Delivery",
"Natural Resource Exploration"
]
}
{
"_id" : ObjectId("6195514a50f8bacf51bdb6ac"),
"onSale" : true,
"name" : "PlayGarra 2078-56",
"price" : 15000,
"weight" : "5 kilograms",
"additionalDetails" : {
"material" : "polysterene",
"moreUses" : [
"Cinematography",
"Wildlife Watching"
]
},
"utility" : [
"Recreation",
"Photography",
"Videography",
"Delivery",
"Natural Resource Exploration"
]
}
{
"_id" : ObjectId("6195514a50f8bacf51bdb6ad"),
"onSale" : true,
"name" : "Frinty Gemini 3X70",
"price" : 55000,
"weight" : "22 kilograms",
"additionalDetails" : {
"material" : "aluminum",
"moreUses" : [
"Cinematography",
"Wildlife Watching",
"Precision Agriculture",
"Land Inspection",
"Water Inspection",
"Videography"
]
},
"utility" : [
"Recreation",
"Photography",
"Videography",
"Delivery",
"Natural Resource Exploration"
]
}
{
"_id" : ObjectId("6195514a50f8bacf51bdb6ae"),
"onSale" : true,
"name" : "Rilche Gabbana Flier RG950",
"price" : 110000,
"weight" : "100 kilograms",
"additionalDetails" : {
"material" : "lithium",
"moreUses" : [
"Cinematography",
"Wildlife Watching",
"Precision Agriculture",
"Land Inspection",
"Water Inspection",
"Videography"
]
},
"utility" : [
"Recreation",
"Photography",
"Videography",
"Delivery",
"Natural Resource Exploration"
]
}
{
"_id" : ObjectId("619924ef4b1ff00cfd5eb3ae"),
"onSale" : true,
"name" : "Caminara Frucha FCZ-89",
"price" : 67800,
"weight" : "35 kilograms",
"additionalDetails" : {
"material" : "glass fibre",
"moreUses" : [ ]
},
"utility" : [
"Recreation",
"Photography",
"Videography",
"Delivery",
"Natural Resource Exploration"
]
}
{
"_id" : ObjectId("619924ef4b1ff00cfd5eb3af"),
"onSale" : true,
"name" : "Azehsra Chelske AZC-HYU56",
"price" : 45600,
"weight" : "32 kilograms",
"additionalDetails" : {
"material" : "carbon fibre",
"moreUses" : [
"Cinematography",
"Wildlife Watching",
"Precision Agriculture"
]
},
"utility" : null
}
{
"_id" : ObjectId("619924ef4b1ff00cfd5eb3b0"),
"onSale" : true,
"name" : "Hazela Gunce QY999",
"price" : 33900,
"weight" : "20 kilograms",
"additionalDetails" : {
"material" : "carbon fibre",
"moreUses" : [
"Videography",
"Wildlife Watching",
"Photography"
]
},
"utility" : [
undefined
]
}
Let’s now see the different examples of counting documents of a collection by grouping them based on some criteria provided to the $group pipeline stage.
Example 1:
Counting documents by grouping them based on their prices.
> db.drones.aggregate([
... {"$group":{_id:"$price",counter:{$sum:1}}}])
{ "_id" : 33900, "counter" : 1 }
{ "_id" : 99500, "counter" : 1 }
{ "_id" : 120500, "counter" : 1 }
{ "_id" : 15000, "counter" : 1 }
{ "_id" : 55000, "counter" : 1 }
{ "_id" : 77500, "counter" : 1 }
{ "_id" : 23500, "counter" : 1 }
{ "_id" : 67800, "counter" : 1 }
{ "_id" : 110000, "counter" : 1 }
{ "_id" : 45600, "counter" : 1 }
{ "_id" : 87600, "counter" : 1 }
Example 2:
Counting documents by grouping them based on their names.
> db.drones.aggregate([
... {"$group":{_id:"$name",counter:{$sum:1}}}]);
{ "_id" : "PlayGarra 2078-56", "counter" : 1 }
{ "_id" : "Sifinist Croma AX", "counter" : 1 }
{ "_id" : "Drovce Finnifield FR-7", "counter" : 1 }
{ "_id" : "Azehsra Chelske AZC-HYU56", "counter" : 1 }
{ "_id" : "Frinty Gemini 3X70", "counter" : 1 }
{ "_id" : "Rilche Gabbana Flier RG950", "counter" : 1 }
{ "_id" : "Caminara Frucha FCZ-89", "counter" : 1 }
{ "_id" : "X-Strimmer Eye", "counter" : 1 }
{ "_id" : "Nimbari Gryphon Medeta 65", "counter" : 1 }
{ "_id" : "Khai Balemosh Shefqa TRX", "counter" : 1 }
{ "_id" : "Hazela Gunce QY999", "counter" : 1 }
Example 3:
Counting documents by grouping them based on the “onSale” field to see how many are false and how many are true.
> db.drones.aggregate([
... {"$group":{_id:"$onSale",counter:{$sum:1}}}])
{ "_id" : false, "counter" : 5 }
{ "_id" : true, "counter" : 6 }
Here we can see that the counter value is not 1 like in the previous examples because, in the previous example, the field value is unique for each document, whereas here the “onSell” field is true or false in multiple documents, that’s why in the result we can see that the “onSell” field in 5 documents is equal to false and in 6 documents it is true.
Example of Counting Documents Using $group by Querying on Nested Field
We can also count documents after grouping them on the bases of a nested field. We have to use dot notation to access the nested document or field.
Example:
Counting documents by grouping them based on the material nested field.
> db.drones.aggregate([
... {"$group":{_id:"$additionalDetails.material",counter:{$sum:1}}}])
{ "_id" : "glass fiber", "counter" : 1 }
{ "_id" : "lithium", "counter" : 2 }
{ "_id" : "polysterene", "counter" : 2 }
{ "_id" : "carbon fibre", "counter" : 2 }
{ "_id" : "carbon fiber", "counter" : 1 }
{ "_id" : "aluminum", "counter" : 2 }
{ "_id" : "glass fibre", "counter" : 1 }
Here we have got the count based on the material field.
Conclusion
In this tutorial, we have learned to use the $group function and seen how to use it to perform a count operation. This tutorial can be difficult to understand as we have learned a lot of new concepts, make sure you have a good understanding of MongoDB Arregrate which helps you to understand these concepts more easily.
References
https://docs.mongodb.com/manual/reference/operator/aggregation/group/#mongodb-pipeline-pipe.-group
https://stackoverflow.com/questions/23116330/mongodb-select-count-group-by