mongodb mapreduce

summarize mongodb



Fusionando dos colecciones en MongoDB (2)

Esto es similar a una pregunta que se hizo en los Grupos de Google de los usuarios de MongoDB.
https://groups.google.com/group/mongodb-user/browse_thread/thread/60a8b683e2626ada?pli=1

La respuesta hace referencia a un tutorial en línea que se parece a su ejemplo: http://tebros.com/2011/07/using-mongodb-mapreduce-to-join-2-collections/

Para obtener más información sobre MapReduce en MongoDB, consulte la documentación: http://www.mongodb.org/display/DOCS/MapReduce

Además, hay una guía paso a paso útil sobre cómo funciona una operación MapReduce en la sección "Extras" del artículo del libro de cocina de MongoDB titulado "Encontrar valores http://cookbook.mongodb.org/patterns/finding_max_and_min/ con documentos versionados": http://cookbook.mongodb.org/patterns/finding_max_and_min/

Perdóneme si ya ha leído algunos de los documentos a los que se hace referencia. Los he incluido para el beneficio de otros usuarios que pueden estar leyendo esta publicación y nuevos en el uso de MapReduce en MongoDB

Es importante que las salidas de las declaraciones ''emitir'' en las funciones del Mapa coincidan con las salidas de la función Reducir. Si solo hay una salida de documento por la función Mapa, es posible que la función Reducir no se ejecute en absoluto, y entonces su colección de salida tendrá documentos no coincidentes.

He modificado ligeramente las declaraciones de su mapa para emitir documentos en el formato de su salida deseada, con dos matrices de "clases" separadas.
También he modificado su declaración de reducción para agregar nuevas clases a las matrices classes_1 y classes_2, solo si aún no existen.

var mapDetails = function(){ var output = {studentid: this.studentid, classes_1: [], classes_2: [], year: this.year, overall: 0, subscore: 0} if (this.year == 1) { output.classes_1 = this.classes; } if (this.year == 2) { output.classes_2 = this.classes; } emit(this.studentid, output); }; var mapGpas = function() { emit(this.studentid, {studentid: this.studentid, classes_1: [], classes_2: [], year: 0, overall: this.overall, subscore: this.subscore}); }; var r = function(key, values) { var outs = { studentid: "0", classes_1: [], classes_2: [], overall: 0, subscore: 0}; values.forEach(function(v){ outs.studentid = v.studentid; v.classes_1.forEach(function(class){if(outs.classes_1.indexOf(class)==-1){outs.classes_1.push(class)}}) v.classes_2.forEach(function(class){if(outs.classes_2.indexOf(class)==-1){outs.classes_2.push(class)}}) if (v.year == 0) { outs.overall = v.overall; outs.subscore = v.subscore; } }); return outs; }; res = db.details.mapReduce(mapDetails, r, {out: {reduce: ''joined''}}) res = db.gpas.mapReduce(mapGpas, r, {out: {reduce: ''joined''}})

La ejecución de las dos operaciones de MapReduce da como resultado la siguiente colección, que coincide con el formato deseado:

> db.joined.find() { "_id" : "12345a", "value" : { "studentid" : "12345a", "classes_1" : [ 1, 17, 19, 21 ], "classes_2" : [ 32, 91, 101, 217 ], "overall" : 97, "subscore" : 1 } } { "_id" : "24680a", "value" : { "studentid" : "24680a", "classes_1" : [ 1, 11, 18, 22 ], "classes_2" : [ ], "overall" : 76, "subscore" : 2 } } { "_id" : "98765a", "value" : { "studentid" : "98765a", "classes_1" : [ 2, 12, 19, 22 ], "classes_2" : [ 32, 99, 110, 215 ], "overall" : 85, "subscore" : 5 } } >

MapReduce siempre genera documentos en forma de {_id: "id", valor: "valor"} Hay más información disponible sobre cómo trabajar con sub-documentos en el documento titulado "Notación de puntos (Llegar a objetos)": http://www.mongodb.org/display/DOCS/Dot+Notation+%28Reaching+into+Objects%29

Si desea que la salida de MapReduce aparezca en un formato diferente, deberá hacerlo mediante programación en su aplicación.

Con suerte, esto mejorará su comprensión de MapReduce y lo acercará un paso más a la producción de la colección de salida deseada. ¡Buena suerte!

He estado tratando de usar MapReduce en MongoDB para hacer lo que creo que es un procedimiento simple. No sé si este es el enfoque correcto, o si debería usar MapReduce. Busqué en Google las palabras clave que pensé e intenté golpear los documentos donde pensé que tendría más éxito, pero nada. Tal vez estoy pensando demasiado en esto?

Tengo dos colecciones: details y gpas

details se componen de un montón de documentos (3+ millones). El elemento studentid se puede repetir dos veces, una para cada year , como lo siguiente:

{ "_id" : ObjectId("4d49b7yah5b6d8372v640100"), "classes" : [1,17,19,21], "studentid" : "12345a", "year" : 1} { "_id" : ObjectId("4d76b7oij7s2d8372v640100"), "classes" : [2,12,19,22], "studentid" : "98765a", "year" : 1} { "_id" : ObjectId("4d49b7oij7s2d8372v640100"), "classes" : [32,91,101,217], "studentid" : "12345a", "year" : 2} { "_id" : ObjectId("4d76b7rty7s2d8372v640100"), "classes" : [1,11,18,22], "studentid" : "24680a", "year" : 1} { "_id" : ObjectId("4d49b7oij7s2d8856v640100"), "classes" : [32,99,110,215], "studentid" : "98765a", "year" : 2} ...

gpas tiene elementos con los mismos details gpas . Solo una entrada por studentid , como esta:

{ "_id" : ObjectId("4d49b7yah5b6d8372v640111"), "studentid" : "12345a", "overall" : 97, "subscore": 1} { "_id" : ObjectId("4f76b7oij7s2d8372v640213"), "studentid" : "98765a", "overall" : 85, "subscore": 5} { "_id" : ObjectId("4j49b7oij7s2d8372v640871"), "studentid" : "24680a", "overall" : 76, "subscore": 2} ...

Al final, quiero tener una colección con una fila para cada estudiante en este formato:

{ "_id" : ObjectId("4d49b7yah5b6d8372v640111"), "studentid" : "12345a", "classes_1": [1,17,19,21], "classes_2": [32,91,101,217], "overall" : 97, "subscore": 1} { "_id" : ObjectId("4f76b7oij7s2d8372v640213"), "studentid" : "98765a", "classes_1": [2,12,19,22], "classes_2": [32,99,110,215], "overall" : 85, "subscore": 5} { "_id" : ObjectId("4j49b7oij7s2d8372v640871"), "studentid" : "24680a", "classes_1": [1,11,18,22], "classes_2": [], "overall" : 76, "subscore": 2} ...

La forma en que iba a hacer esto era ejecutar MapReduce de esta manera:

var mapDetails = function() { emit(this.studentid, {studentid: this.studentid, classes: this.classes, year: this.year, overall: 0, subscore: 0}); }; var mapGpas = function() { emit(this.studentid, {studentid: this.studentid, classes: [], year: 0, overall: this.overall, subscore: this.subscore}); }; var reduce = function(key, values) { var outs = { studentid: "0", classes_1: [], classes_2: [], overall: 0, subscore: 0}; values.forEach(function(value) { if (value.year == 0) { outs.overall = value.overall; outs.subscore = value.subscore; } else { if (value.year == 1) { outs.classes_1 = value.classes; } if (value.year == 2) { outs.classes_2 = value.classes; } outs.studentid = value.studentid; } }); return outs; }; res = db.details.mapReduce(mapDetails, reduce, {out: {reduce: ''joined''}}) res = db.gpas.mapReduce(mapGpas, reduce, {out: {reduce: ''joined''}})

Pero cuando lo ejecuto, esta es mi colección resultante:

{ "_id" : "12345a", "value" : { "studentid" : "12345a", "classes_1" : [ ], "classes_2" : [ ], "overall" : 97, "subscore" : 1 } } { "_id" : "98765a", "value" : { "studentid" : "98765a", "classes_1" : [ ], "classes_2" : [ ], "overall" : 85, "subscore" : 5 } } { "_id" : "24680a", "value" : { "studentid" : "24680a", "classes_1" : [ ], "classes_2" : [ ], "overall" : 76, "subscore" : 2 } }

Me estoy perdiendo las matrices de clases.

Además, aparte, ¿cómo accedo a los elementos en el elemento de value MapReduce resultante? ¿MapReduce siempre genera un value o como se llame?


No puede usar m / r para esto, ya que está diseñado para aplicarse solo en una colección. La lectura de más de una colección romperá la compatibilidad de fragmentación y, por lo tanto, no está permitida. Puede hacer lo que quiera con el nuevo marco de agregación (2.1+) o hacerlo dentro de su aplicación.