Reputation: 1260
In a MongoDB collection, there is data nested in an absence
array.
{
"_id" : ObjectId("5c6c62f3d0e85e6ae3a8c842"),
"absence" : [
{
"date" : ISODate("2017-05-10T17:00:00.000-07:00"),
"code" : "E",
"type" : "E",
"isPartial" : false
},
{
"date" : ISODate("2018-02-24T16:00:00.000-08:00"),
"code" : "W",
"type" : "E",
"isPartial" : false
},
{
"date" : ISODate("2018-02-23T16:00:00.000-08:00"),
"code" : "E",
"type" : "E",
"isPartial" : false
},
{
"date" : ISODate("2018-02-21T16:00:00.000-08:00"),
"code" : "U",
"type" : "U",
"isPartial" : false
},
{
"date" : ISODate("2018-02-20T16:00:00.000-08:00"),
"code" : "R",
"type" : "E",
"isPartial" : false
}
]
}
I'd like to aggregate by absence.type
to return a count of every type and the total number of absence
children. The results might look like:
{
"_id" : ObjectId("5c6c62f3d0e85e6ae3a8c842"),
"U" : 1,
"E" : 4,
"total" : 5
}
There are several similar questions posted here but I'm yet to successfully adapt the answers my schema. Any help is greatly appreciated.
Also, are there GUI modeling tools to help with MongoDB query building? The transition from RDBMS queries to the Mongo aggregation pipeline has been quite difficult.
Upvotes: 1
Views: 900
Reputation: 890
If you know all the possible values of "absence.type" then $filter the array on the value and compute the $size of the filtered array. This won't work if you don't know all the possible values in the "absence.type".
db.col.aggregate([
{ $project: { U: { $size: { $filter: { input: "$absence", as: "a", cond: { $eq: [ "$$a.type", "U"]} }}},
E: { $size: { $filter: { input: "$absence", as: "a", cond: { $eq: [ "$$a.type", "E"]} }}} }},
{ $project: { total: { $add: [ "$U", "$E" ]}, U: 1, E: 1}},
])
Upvotes: 0
Reputation: 49945
You can use below aggregation:
db.col.aggregate([
{
$unwind: "$absence"
},
{
$group: {
_id: { _id: "$_id", type: "$absence.type" },
count: { $sum: 1 }
}
},
{
$group: {
_id: "$_id._id",
types: { $push: { k: "$_id.type", v: "$count" } },
total: { $sum: "$count" }
}
},
{
$replaceRoot: {
newRoot: {
$mergeObjects: [ "$$ROOT", { $arrayToObject: "$types" } ]
}
}
},
{
$project: {
types: 0
}
}
])
$unwind allows you to get single document per absence
. Then you need double $group, first one to count by type
and _id
and second one to aggregate the data per _id
. Having one document per _id
you just need $replaceRoot with $mergeObjects to promote your dynamically created keys and values (by $arrayToObject) to the root level.
output:
{ "_id" : ObjectId("5c6c62f3d0e85e6ae3a8c842"), "total" : 5, "U" : 1, "E" : 4 }
Upvotes: 2