Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoDB: Mapreduce: reduce->multiple not supported yet

Tags:

mongodb

I have a MongoDB collection (named "catalog") containing about 5 astronomical catalogs. Several of these catalogs reference each other, so one of the the documents might look something like this:

{ "_id" : ObjectId("4ec574a68e4e7a519166015f"), "bii" : 20.9519, "class" : 2480, "cpdname" : "CPD -21 6109", "decdeg" : -21.8417, "decpm" : 0.004, "dmname" : "-21 4299", "hdname" : "HD 145612", "lii" : 352.8556, "name" : "PPM 265262", "ppmname" : "PPM 265262", "radeg" : 243.2005, "rapm" : 0.0012, "vmag" : 9.6, "xref" : [ ] }

What I want to do is use mapreduce to move the fields such as "hdname","ppmname", etc into the xref array (then unset them).

So I try to do this one at a time, starting with the hdname field. Here are the map and reduce functions:

map = function() {
    for (var hdname in this.hdname) {
        emit(this._id,this.hdname);
    }
}


reduce = function(key, values) {
    var result = [];
    for (var hdname in values) {
        result.push(hdname);
    }
    return result;
}

I try running the following command in the mongo shell:

db.catalog.mapReduce(map, reduce,"catalog2");

Unfortunately, I get the following error:

Thu Nov 17 15:52:17 uncaught exception: map reduce failed:{
    "assertion" : "reduce -> multiple not supported yet",
    "assertionCode" : 10075,
    "errmsg" : "db assertion failure",
    "ok" : 0
}

Obviously I'm a newbie... can anyone help?

Jason

like image 836
Jason Avatar asked Nov 17 '11 22:11

Jason


3 Answers

The documentation says "Currently, the return value from a reduce function cannot be an array (it's typically an object or a number)."

So create an object instead and wrap your array in that. Make sure also that the output of reduce is the same as the input type, so you'll need to emit a similar value in the map operation.

BUT ... why use Map-Reduce to do this? If you emit the _id value there's nothing to reduce as each key will be unique. Why not just iterate over the collection copying the values and updating each record one by one?

like image 183
Ian Mercer Avatar answered Nov 18 '22 20:11

Ian Mercer


I recently needed to return a dictionary as well in my reduce step. Solved this by doing

return values.toString();

in my reducer code. After that I have to parse the result to get individuals, but that wasn't a big deal...

like image 38
jkklapp Avatar answered Nov 18 '22 20:11

jkklapp


try to return object in reduce function

reduce = function(key, values) {
   var result = [];
   for (var hdname in values) {
     result.push(hdname);
   }
   return {value:result};
}
like image 1
Đọc truyện hay Avatar answered Nov 18 '22 21:11

Đọc truyện hay