Getting a cumulative sum by map reduce function

773 views
Skip to first unread message

Eun-Jeong Joyce Shin

unread,
Jan 24, 2017, 3:42:54 PM1/24/17
to mongodb-user
I am trying to get cumulative sum in regards to specific date and time, type as well as per same user. First off, here's my dataset.

    {
    "_id" : ObjectId("5885b8fb3b765e1980f1dc3e"),
"Date" : "12/21/2016",
"Time" : "11:30:00",
"Temperature" : 70.5,
"User" : "C",
"ThermalDiscomfort" : -1,
"Type" : "MEDIAN",
"settingID" : ObjectId("58819cfaf16a780258cee2ea")}
    {
"_id" : ObjectId("5885b8fe3b765e1980f1dede"),
"Date" : "12/21/2016",
"Time" : "11:30:00",
"Temperature" : 70.5,
"User" : "D",
"ThermalDiscomfort" : -1,
"Type" : "MEDIAN",
"settingID" : ObjectId("58819cfaf16a780258cee2ea")}

Now, I am trying to get cumulative sum value over "ThermalDiscomfort" column. My expected output is as following:

    {
"_id" : ObjectId("5885b8fe3b765e1980f1dede"),
"Date" : "12/21/2016",
"Time" : "11:30:00",
"User" : "D",
"ATDC" : 2, // Which is a sum of abstract values of "ThermalDiscomfort" for certain date and user over the time period.
"Type" : "MEDIAN",
"settingID" : ObjectId("58819cfaf16a780258cee2ea")}

And here's my code:

    String map = "function() {" +
"var value = this.ThermalDiscomfort;" +
"if(value < 0) value = -value;" +
"emit({Date: this.Date, Time: this.Time, User: this.User, Type: this.Type}, value);"
+ "};";
String reduce = "function(key, valueATDC) {" +
"return Array.sum(valueATDC);" +
"};";

    BsonDocument query = new BsonDocument("Type", new BsonString(option.toString()));
    MapReduceIterable<Document> atdcDoc = thermalDiscomfortCollection.mapReduce(map, reduce).filter(query);

This function does not produce what I expect. It is not a cumulative sum of abstract values. Would you give comments on this? I am using mongo java driver version 3.2.2.

Kevin Adistambha

unread,
Feb 1, 2017, 12:54:15 AM2/1/17
to mongodb-user

Hi

This function does not produce what I expect. It is not a cumulative sum of abstract values. Would you give comments on this? I am using mongo java driver version 3.2.2.

If I understand correctly, I think you mean “absolute values” instead of “abstract values”. Either way, I would suggest you to use the aggregation framework instead of using map-reduce.

As an example, using the two document examples you posted, you can get the sum of the ThermalDiscomfort field across all documents in the mongo shell with:

> db.test.aggregate([{$group:{_id:null, value:{$sum:{$abs:'$ThermalDiscomfort'}}}}])
{ "_id" : null, "value" : 2 }

Similar result can be achieved using the Java driver (version 3.2.2):

MongoIterable<Document> agg = collection.aggregate(
    Arrays.asList(
        group(null, sum("value", new Document("$abs", "$ThermalDiscomfort")))
    )
);
for(Document doc : agg) {
    System.out.println(doc.toJson());
}

which results in:

{ "_id" : null, "value" : 2.0 }

Please note that I used the $abs operator in the above example, which is available on MongoDB 3.2 and newer. Also, I didn’t take into account the date and the user fields in the example. Please modify the example as you require to achieve what you need.

You might find the following links helpful:

Best regards,
Kevin

Reply all
Reply to author
Forward
0 new messages