Mathew
Mathew

Reputation: 71

MongoDB - mapReduce

I've got mongoDB collection, where each doc looks like:

{
    "_id": 1,
    "name": "Aurelia Menendez",
    "scores": [{
        "score": 60.06045071030959,
        "type": "exam"
    }, {
        "score": 52.79790691903873,
        "type": "quiz"
    }, {
        "score": 71.76133439165544,
        "type": "homework"
    }]
}

I try to run:

db.students.mapReduce(
    function() {
        emit(this._id, this.scores.map(a => a.score));
     },
     function(_id, values) {
        //here i try:
        1) return values.reduce((a, b) => a + b);
        2) return values.reduce((a, b) => a + b, 0);
        3) return Array.sum(values);
     },
    { out: "total_scores" }
 )

What I get? I get collection where each doc look like:

  1. "value" is array:
{
    "_id": 20,
    "value": [42.17439799514388, 71.99314840599558, 81.23972632069464]
}
  1. "value" is value
{
    "_id": 188,
    "value": "060.314725741828,41.12327471818652,74.8699176311771"
}
  1. "value" is array
{
    "_id": 193,
    "value": [47.67196715489599, 41.55743490493954, 70.4612811769744]
}

Why I don't get sum of elements? When I try this.scores or this.scores.score instead of this.scores.map(a => a.score), I have all attributes, or null values.

Maybe someone have any idea, what did I wrong?

Upvotes: 2

Views: 387

Answers (1)

Cuong Bui
Cuong Bui

Reputation: 36

You should use Aggregation instead of MapReduce. This is note from official Mongo document

Aggregation pipeline provides better performance and a more coherent interface than map-reduce, and various map-reduce operations can be rewritten using aggregation pipeline operators, such as $group, $merge, $accumulator, etc..

The steps I used to get the aggregation stages:

  1. Use MongoDB Compass and open Aggregations Tab to test aggregation.
  2. Add stages : $match : filter student, $unwind: flatten array of score, $group : get the total by sum all scores.
  3. Convert to code

The result is

[
  {
    '$match': {
      'name': 'Aurelia Menendez'
    }
  }, {
    '$unwind': {
      'path': '$scores'
    }
  }, {
    '$group': {
      '_id': '$_id', 
      'total': {
        '$sum': '$scores.score'
      }
    }
  }
]

MongoDB Compass Result

Upvotes: 2

Related Questions