Reputation: 1721
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
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