Ceci est similaire à une question qui a été posée sur les groupes Google des utilisateurs de MongoDB.
https://groups.google.com/group/mongodb-user/browse_thread/thread/60a8b683e2626ada?pli=1
La réponse fait référence à un didacticiel en ligne qui ressemble à votre exemple :http://tebros.com/2011/07/using-mongodb-mapreduce-to-join-2-collections/
Pour plus d'informations sur MapReduce dans MongoDB, veuillez consulter la documentation :http://www.mongodb.org/display/DOCS/MapReduce
De plus, il existe une procédure pas à pas utile sur le fonctionnement d'une opération MapReduce dans la section "Extras" de l'article MongoDB Cookbook intitulé "Finding Max And Min Values with Versioned Documents":http://cookbook.mongodb. org/patterns/finding_max_and_min/
Pardonnez-moi si vous avez déjà lu certains des documents référencés. Je les ai inclus pour le bénéfice d'autres utilisateurs qui lisent peut-être cet article et qui découvrent l'utilisation de MapReduce dans MongoDB
Il est important que les sorties des instructions 'emit' dans les fonctions Map correspondent aux sorties de la fonction Reduce. S'il n'y a qu'un seul document généré par la fonction Map, la fonction Reduce peut ne pas être exécutée du tout, et votre collection de sortie contiendra alors des documents non concordants.
J'ai légèrement modifié vos instructions map pour émettre des documents dans le format de sortie souhaité, avec deux tableaux "classes" distincts.
J'ai également retravaillé votre instruction reduce pour ajouter de nouvelles classes aux tableaux classes_1 et classes_2, uniquement si ils n'existent pas déjà.
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'}})
L'exécution des deux opérations MapReduce donne la collection suivante, qui correspond au format souhaité :
> 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 produit toujours des documents sous la forme de {_id :"id", value:"value"}Il y a plus d'informations disponibles sur le travail avec les sous-documents dans le document intitulé "Dot Notation (Reaching into Objects)":http:/ /www.mongodb.org/display/DOCS/Dot+Notation+%28Reaching+into+Objects%29
Si vous souhaitez que la sortie de MapReduce apparaisse dans un format différent, vous devrez le faire par programmation dans votre application.
J'espère que cela améliorera votre compréhension de MapReduce et vous rapprochera un peu plus de la production de la collection de sortie souhaitée. Bonne chance !