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.

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…