Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle division by zero in MongoDB aggregation framework

Tags:

I have a collection of items that can be upvoted or downvoted.

{"_id" : 1, "name": "foo", "upvotes" : 30, "downvotes" : 10} {"_id" : 2, "name": "bar", "upvotes" : 20, "downvotes" : 0} {"_id" : 3, "name": "baz", "upvotes" : 0,  "downvotes" : 0} 

I'd like to use aggregation to calculate the quality

db.items.aggregate([     {"$project":         {             "name": "$name",             "upvotes": "$upvotes"             "downvotes": "$downvotes",             "quality": {"$divide":["$upvotes", "$downvotes"]}         }     },     {"$sort": {"quality":-1}} ]); 

Obviously this doesn't work, because of division by zero. I need to implement appropriate conditioning:

if upvotes != 0 and downvotes == 0 then the quality = upvotes if upvotes and downvotes are both 0 then the quality is 0

I tried tweaking downvotes by 1 using ternary idiom. But to no avail.

db.items.aggregate([     {"$project":         {             "name": "$name",             "upvotes": "$upvotes",             "downvotes": "$downvotes" ? "$downvotes": 1         }     },     {"$project":         {             "name": "$name",             "upvotes": "$upvotes"             "downvotes": "$downvotes",             "quality": {"$divide":["$upvotes", "$downvotes"]}         }     },     {"$sort": {"quality":-1}} ]); 

How can I integrate this kind of conditioning within mongodb aggregation framework?

like image 283
gwaramadze Avatar asked Apr 03 '14 14:04

gwaramadze


People also ask

How do you divide in MongoDB?

In MongoDB, the $divide aggregation pipeline operator divides one number by another and returns the result. To use $divide , pass the numbers in an array. The $divide operator will divide the first number by the second number. In other words, the first number is the dividend, and the second number is the divisor.

Can we use $and in aggregate MongoDB?

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.

Which aggregate method is preferred for use by MongoDB?

The aggregate() Method For the aggregation in MongoDB, you should use aggregate() method.

How do I sort an array in MongoDB aggregation?

To sort the whole array by value, or to sort by array elements that are not documents, identify the input array and specify 1 for an ascending sort or -1 for descending sort in the sortBy parameter.


2 Answers

You might want to use the $cond operator to handle this:

db.items.aggregate([     {"$project":         {             "name": "$name",             "upvotes": "$upvotes",             "downvotes": "$downvotes",             "quality": { $cond: [ { $eq: [ "$downvotes", 0 ] }, "N/A", {"$divide":["$upvotes", "$downvotes"]} ] }         }     },     {"$sort": {"quality":-1}} ]); 
like image 140
Anand Jayabalan Avatar answered Sep 21 '22 18:09

Anand Jayabalan


You want the $cond operator. http://docs.mongodb.org/manual/reference/operator/aggregation/cond/

Something like:

{"$project":   {     "name": "$name",     "upvotes": "$upvotes",     "downvotes": { $cond: [ { $eq: ["$downvotes", 0] }, 1, "$downvotes"] }    } }, 
like image 21
Will Shaver Avatar answered Sep 22 '22 18:09

Will Shaver