Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rounding to 2 decimal places using MongoDB aggregation framework

I am using the mongodb aggregation framework and doing some calculations as shown below

db.RptAgg.aggregate(    {$group: {     _id: {Region: "$RegionTxt", Mth: "$Month"},                ActSls: {$sum:"$ActSls"},     PlnSls: {$sum:"$PlnSls"}   }},   {$project: {     ActSls: 1,     PlnSls: 1,     ActToPln: {$cond: [       {$ne: ["$PlnSls", 0]},        {$multiply: [{$divide: ['$ActSls', '$PlnSls']}, 100]},        0     ]}   }} );  

I am trying to figure out what is the best and easiest way to round my results to 2 decimal places. Following is my result

{   "result": [{     "_id": {       "Region": "East",       "Mth": 201301     },     "ActSls": 72,     "PlnSls": 102,     "ActToPln": 70.58823529411765   }],   "ok": 1 } 

I want "ActToPln" to show 70.59 instead of "ActToPln" : 70.58823529411765, in the results from aggegation framework itself. I want to avoid doing the rounding in my application

Can you please help with the same.

Following is the dataset i used.

{     "_id" : ObjectId("51d67ef69557c507cb172572"),     "RegionTxt" : "East",     "Month" : 201301,     "Date" : "2013-01-01",     "ActSls" : 31,     "PlnSls" : 51 } {     "_id" : ObjectId("51d67ef69557c507cb172573"),     "RegionTxt" : "East",     "Month" : 201301,     "Date" : "2013-01-02",     "ActSls" : 41,     "PlnSls" : 51 } 

Thanks in advance. Nandu

like image 785
user2552537 Avatar asked Jul 05 '13 06:07

user2552537


People also ask

How do I round numbers in MongoDB?

You can use the $round operator in MongoDB to round numeric values to a certain number of decimal places. This particular example rounds the values in the field “value” to one decimal place.

Which aggregation method is preferred for use by MongoDB?

The pipeline provides efficient data aggregation using native operations within MongoDB, and is the preferred method for data aggregation in MongoDB. The aggregation pipeline can operate on a sharded collection. The aggregation pipeline can use indexes to improve its performance during some of its stages.

What is NumberLong in MongoDB?

NumberLong. The mongo shell treats all numbers as floating-point values by default. The mongo shell provides the NumberLong() wrapper to handle 64-bit integers. The NumberLong() wrapper accepts the long as a string: NumberLong("2090845886852")

How aggregation is performed in MongoDB?

In MongoDB, aggregation operations process the data records/documents and return computed results. It collects values from various documents and groups them together and then performs different types of operations on that grouped data like sum, average, minimum, maximum, etc to return a computed result.


2 Answers

There is no $round operator but you can do this in the aggregation framework - doing it in specific order will usually avoid floating point precision issues.

> db.a.save({x:1.23456789}) > db.a.save({x:9.87654321}) > db.a.aggregate([{$project:{ _id:0,           y:{$divide:[               {$subtract:[                       {$multiply:['$x',100]},                       {$mod:[{$multiply:['$x',100]}, 1]}               ]},               100]} }}]) { "y" : 1.23 } { "y" : 9.87 } 

Given the existing pipeline in the problem, replace:

{$multiply:[{$divide: ['$ActSls', '$PlnSls']},100]} 

with

{$divide:[      {$subtract:[            {$multiply:[              {$divide: ['$ActSls','$PlnSls']},              10000           ]},            {$mod:[              {$multiply:[{$divide: ['$ActSls','$PlnSls']}, 10000 ]},              1]}           ]},       100 ]} 

With your sample data points this is the result:

{ "ActSls" : 31, "PlnSls" : 51, "ActToPln" : 60.78 } { "ActSls" : 41, "PlnSls" : 51, "ActToPln" : 80.39 } { "ActSls" : 72, "PlnSls" : 102, "ActToPln" : 70.58 } 
like image 89
Asya Kamsky Avatar answered Sep 22 '22 12:09

Asya Kamsky


Starting Mongo 4.2, there is a new $round aggregation operator which can be used to round a number with a certain precision to a specified decimal place:

{ $round : [ <number>, <place> ] }

Which can be used as such within an aggregation pipeline (here we round xs to 2 decimal places):

// db.collection.insert([{x: 1.23456}, {x: 9.87654}, {x: 0.055543}, {x: 12.345}]) db.collection.aggregate([{ $project: { "rounded_x": { $round: ["$x", 2] }}}]) // [{"rounded_x": 1.23}, {"rounded_x": 9.88}, {"rounded_x": 0.06}, {"rounded_x": 12.35}] 

Note that the place parameter is optional, and omitting it results in rounding to a whole integer (i.e. rounding at 0 decimal places).

like image 28
Xavier Guihot Avatar answered Sep 22 '22 12:09

Xavier Guihot