I run some aggregation queries on MongoDB 3.2. I would like to group documents by a field with an average on another numeric field. I need the average to ignore the 0 values. The problem is I can't entirely filter the document, cause there is another field I need for a count.
Let's illustrate :
This is the structure of my documents:
{"stringToGroupByOn":"foo", "valueToAvg":42, "valueToSum":21}
{"stringToGroupByOn":"foo", "valueToAvg":0, "valueToSum":13}
I can't just filter like this:
db.foobar.aggregate([
{
$match : { valueToAvg : { $gt : 0 } }
},
{
$group : {
_id : '$stringToGroupByOn',
avg : { $avg : '$valueToAvg' },
count : { $sum : '$valueToSum' }
}
}
])
Because I lose the value 13 for the count.
Do you think there is a way to do it in only one query ?
To exclude the _id field from the output documents of the $project stage, specify the exclusion of the _id field by setting it to 0 in the projection document.
Solution 1: In case preservation of all null values[] or null fields in the array itself is not necessary. Filter out the not null elements using $filter , the ( all null elements) array would be empty, filter that out from documents using $match then $sort on values .
You can use $and with aggregation but you don't have to write it, and is implicit using different filters, in fact you can pipe those filters in case one of them needs a different solution.
With aggregate + $match, you get a big monolithic BSON containing all matching documents. With find, you get a cursor to all matching documents. Then you can get each document one by one.
You can use $cond in projection to set null instead of 0
, as null is not considered when using average.
db.avg.aggregate([
{$project:{
_id:1,
valueToSum:1,
stringToGroupByOn:1,
valueToAvg:{$cond:
{ if: { $eq: [ "$valueToAvg", 0 ] },
then: null,
else: "$valueToAvg" }}
}},
{
$group : {
_id : '$stringToGroupByOn',
avg : { $avg : '$valueToAvg' },
count : { $sum : '$valueToSum' }
}
}
output:
{
"_id" : "foo",
"avg" : 42.0,
"count" : 34.0
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With