Raphael
Raphael

Reputation: 1721

MapReduce gives odd result when count == 1

Stack: MongoDB 2.6.5, Mongoid 3.1.6, Ruby 2.1.1

I'm using Mongoid to do some MongoDB Map/Reduce stuff.

Here's the setup:

class User
  include Mongoid::Document

  has_many :given_bonuses, class_name: 'Bonus', inverse_of: :giver
  has_many :received_bonuses, class_name: 'Bonus', inverse_of: :receiver
end

class Bonus
  include Mongoid::Document


  belongs_to :giver, class_name: 'User', inverse_of: :given_bonuses
  belongs_to :receiver, class_name: 'User', inverse_of: :received_bonuses
end

I'm using the following Map/Reduce code:

map = %Q{
  function() {
    emit(this.receiver_id, this.giver_id)
  }
}

reduce = %Q{
  function(key, values) {
    var result = {};
    values.forEach(function(value) {
      if(! result[value]) {
        result[value] = 0;
      }
      result[value] += 1;
    });
    return result;
  }
}

Bonus.all.map_reduce(map, reduce).out(inline: 1)

Let's say I have two or more bonus documents:

> Bonus.count
 => 2
> Bonus.all.to_a
 => [#<Bonus _id: 547612a21dbe8b7859000071, giver_id: "547612441dbe8bf35b000005", receiver_id: "547612531dbe8b4a7200006a">, #<Bonus _id: 547612a21dbe8b78590000f9, giver_id: "547612441dbe8bf35b000005", receiver_id: "547612531dbe8b4a7200006a">]

Then the Map/Reduce result is:

 => [{"_id"=>"547612531dbe8b4a7200006a", "value"=>{"ObjectId(\"547612441dbe8bf35b000005\")"=>2.0}}]

Notice that the value key points to a hash of the form {"ObjectID" => Number}. This is as it should be.

Now let's say I have only one bonus document:

> Bonus.count
 => 1
> Bonus.first
 => #<Bonus _id: 547612a21dbe8b7859000071, giver_id: "547612441dbe8bf35b000005", receiver_id: "547612531dbe8b4a7200006a">

Then the Map/Reduce result is:

 => [{"_id"=>"547612531dbe8b4a7200006a", "value"=>"547612441dbe8bf35b000005"}]

Notice that the schema of the result has changed. It should be:

 => [{"_id"=>"547612531dbe8b4a7200006a", "value"=>{"ObjectId(\"547612441dbe8bf35b000005\")"=>1.0}}]

What's going on here?

Upvotes: 1

Views: 46

Answers (1)

BatScream
BatScream

Reputation: 19700

From the docs:

MongoDB will not call the reduce function for a key that has only a single value. The values argument is an array whose elements are the value objects that are “mapped” to the key.

In the first case the key this.receiver_id, has two documents in its group and hence the reduce function is invoked for that key.

In the second case when your emitted key has only one record in its group, the reduce function won't be called at all.

So the value(this.giver_id) that you emit for the key, is being displayed as emitted without being reduced, there is no need for it to be reduced further.

Upvotes: 1

Related Questions