How to map/reduce two MongoDB collections

Hi Guy’s,

I am new to map / reduce and trying to figure out a way to collect the
following data using map / reduce instead doing it my (slow) application
logic:

I have a collection ‘challenge’ with a 1:n relation to a collection
‘tasks’. Now I’d like to receive an array of results that gives top
five heightest scored challenge.

For map I tried something like:

map = function () {
emit(this.user_id, { count:1 });
}

and reduce:

reduce = function (key, score) {
var sum = 0;
score.forEach(function(doc){ sum += 1; });
return { count:sum };
}

I fired this against my tasks collection:

var mr = db.tasks.mapReduce(map, reduce, { out: “results” });
But I get crucial results when querying:

db[mr.result].find();
I am using Mongoid on Rails and am completely lost with it. Can someone
point me into the right direction?

my data something like this

/* 13 */
{
“_id” : ObjectId(“4ef1a6a454b53001a4000067”),
“user_id” : “100002573213371”,
“title” : “social who wins”,
“description” : “social who wins”,
“updated_at” : new Date(“Wed, 21 Dec 2011 14:58:04 GMT +05:30”),
“created_at” : new Date(“Wed, 21 Dec 2011 14:58:04 GMT +05:30”),
“tasks” : [{
“is_complete” : 0,
“score_by” : “Check box:1 for checking off the task”,
“score” : “5”,
“name” : “task no 1”,
“_id” : ObjectId(“4ef1a6a454b53001a4000068”)
}, {
“is_complete” : 0,
“score_by” : “Self-report number”,
“score” : “6”,
“name” : “task no 2”,
“_id” : ObjectId(“4ef1a6a454b53001a4000069”)
}],
}

/* 14 */
{
“_id” : ObjectId(“4ef1a6a454b53001a400006d”),
“canCompleteBeforeTasks” : true,
“challenge_id” : ObjectId(“4ef1a6a454b53001a4000067”),
“created_at” : new Date(“Wed, 21 Dec 2011 14:58:04 GMT +05:30”),
“description” : “social who wins”,
“tasks” : [{
“is_complete” : 0,
“score_by” : “Check box:1 for checking off the task”,
“score” : “5”,
“name” : “task no 1”,
“_id” : ObjectId(“4ef1a6a454b53001a400006e”)
}, {
“is_complete” : 0,
“score_by” : “Self-report number”,
“score” : “7”,
“name” : “task no 2”,
“_id” : ObjectId(“4ef1a6a454b53001a400006f”)
}],
“title” : “social who wins”,
“updated_at” : new Date(“Wed, 21 Dec 2011 14:58:04 GMT +05:30”),
“user_id” : “100003135115833”
}

/* 15 */
{
“_id” : ObjectId(“4ef1a6a454b53001a4000073”),
“challenge_id” : ObjectId(“4ef1a6a454b53001a4000067”),
“created_at” : new Date(“Wed, 21 Dec 2011 14:58:04 GMT +05:30”),
“description” : “social who wins”,
“tasks” : [{
“is_complete” : 0,
“score_by” : “Check box:1 for checking off the task”,
“score” : “5”,
“name” : “task no 1”,
“_id” : ObjectId(“4ef1a6a454b53001a4000074”)
}, {
“is_complete” : 0,
“score_by” : “Self-report number”,
“score” : “8”,
“name” : “task no 2”,
“_id” : ObjectId(“4ef1a6a454b53001a4000075”)
}],
“title” : “social who wins”,
“updated_at” : new Date(“Wed, 21 Dec 2011 14:58:04 GMT +05:30”),
“user_id” : “100003174704960”
}

Thx in advance.

++++++++++++++++++
Pravin M.

hi all,

After continuous 10 hours work i fixed it out. below is the code which i
written in challenge model.

def self.task_score_map
<<-MAP
function() {
this.tasks.forEach(function(aTask) {
emit(aTask.score, {score: aTask.score});
});
}
MAP
end

def self.task_score_reduce
<<-REDUCE
function(key, values) {
var sum = 0;
values.forEach(function(aScore) {
sum += parseInt(aScore.score);
});
return sum;
}
REDUCE
end

def self.task_score_build(opts)
self.collection.map_reduce(self.task_score_map,
self.task_score_reduce,
opts)
end

def self.task_score(opts={})
hash = opts.merge({
:out => {:inline => true},
:raw => true
})
self.task_score_build(hash).find()
end

and this is result

#<Enumerator: {“results”=>[{"_id"=>“10”, “value”=>{“score”=>“10”}},
{"_id"=>“11”, “value”=>{“score”=>“11”}}, {"_id"=>“5”, “value”=>30.0},
{"_id"=>“6”, “value”=>{“score”=>“6”}}, {"_id"=>“7”,
“value”=>{“score”=>“7”}}, {"_id"=>“8”, “value”=>{“score”=>“8”}},
{"_id"=>“9”, “value”=>{“score”=>“9”}}], “timeMillis”=>0,
“counts”=>{“input”=>6, “emit”=>12, “reduce”=>1, “output”=>7},
“ok”=>1.0}:find>

i m sorting this a/c to score. but i need a/c to user_id. here user_id
belongs to challenge model.

“_id” : ObjectId(“4ef1a6a454b53001a4000067”),
“user_id” : “100002573213371”,
“title” : “social who wins”,
“description” : “social who wins”,
“updated_at” : new Date(“Wed, 21 Dec 2011 14:58:04 GMT +05:30”),
“created_at” : new Date(“Wed, 21 Dec 2011 14:58:04 GMT +05:30”),
“tasks” : [{
“is_complete” : 0,
“score_by” : “Check box:1 for checking off the task”,
“score” : “5”,
“name” : “task no 1”,
“_id” : ObjectId(“4ef1a6a454b53001a4000068”)
}, {
“is_complete” : 0,
“score_by” : “Self-report number”,
“score” : “6”,
“name” : “task no 2”,
“_id” : ObjectId(“4ef1a6a454b53001a4000069”)
}],
}

i need to pass user_id instead of score.

def self.task_score_map
<<-MAP
function() {
this.tasks.forEach(function(aTask) {
emit(this.user_id, {score: aTask.score});
});
}
MAP
end

any idea…