How to sum objects in array by each id, count average sum, set in order with condition How to sum objects in array by each id, count average sum, set in order with condition mongoose mongoose

How to sum objects in array by each id, count average sum, set in order with condition


I see you have already written javascript loop code to group your documents by startingNumber and then sum the category values, and you just wanted input on how best to sort that using underscore.js.

However, I believe it would be better and simpler to use MongoDB's aggregation framework to do the grouping, summing and sorting for you. You had also said you wanted a counted average so my sample code calculates count and average too.

If I load your sample data:

db.catdata.insert([  {categoryFive:   1, categoryFour:   1, categoryThree:   1,    categoryTwo:    1, categoryOne:    1, startingNumber:  1},  {categoryFive:   2, categoryFour:   1, categoryThree:   2,    categoryTwo:    1, categoryOne:    2, startingNumber:  1},  {categoryFive:   1, categoryFour:   1, categoryThree:   1,    categoryTwo:    1, categoryOne:    1, startingNumber:  2},  {categoryFive:  20, categoryFour:   1, categoryThree:  20,    categoryTwo:   20, categoryOne:   20, startingNumber:  1},  {categoryFive: 100, categoryFour: 100, categoryThree: 100,    categoryTwo:  100, categoryOne:  100, startingNumber:  2}]) ;

then this statement:

db.catdata.aggregate([    {"$project" : {"startingNumber":1,           "cats1to5":{$add:["$categoryFive", "$categoryFour",            "$categoryThree", "$categoryTwo",  "$categoryOne"]}                  }    }   ,{"$group": {"_id"  : "$startingNumber",  "cntCat":{$sum:1},                "totCat":{$sum:"$cats1to5"}, "avgCat":{$avg:"$cats1to5"}               }    }   ,{$sort : {startingNumber:1}}]);

produces this output:

{ "_id" : 2, "cntCat" : 2, "totCat" : 505, "avgCat" : 252.5 }{ "_id" : 1, "cntCat" : 3, "totCat" : 94, "avgCat" : 31.333333333333332 }


I'm assuming you wanted to find the total score across all categories grouped by the starting number. If so, here goes the solution using underscore.js

// group by startingNumber// each group will have multiple objects denoted by 'objs'var grouped = _.chain(data).groupBy('startingNumber').map(function (objs, startNum) {    // iterate through the objects for the current starting number    var score = _.chain(objs).map(function (obj) {        // remove all keys which are not starting with category        var obj    = _.pick(obj, function (value, key) {            return key.indexOf('category') !== -1;        });        var scores = _.values(obj); // get the scores for each category        // compute the sum across all categories for this object        return _.reduce(scores, function (memo, categoryScore) {            return memo + categoryScore;        }, 0);        // compute the sum across all objects for this group    }).reduce(function (memo, value) {        return memo + value;    }, 0).value();    return {        start: startNum,        score: score    };}).value();