MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Mesclando duas coleções no MongoDB


Isso é semelhante a uma pergunta que foi feita nos Grupos do Google de usuários do MongoDB.
https://groups.google.com/group/mongodb-user/browse_thread/thread/60a8b683e2626ada?pli=1

A resposta faz referência a um tutorial on-line semelhante ao seu exemplo:http://tebros.com/2011/07/using-mongodb-mapreduce-to-join-2-collections/

Para obter mais informações sobre MapReduce no MongoDB, consulte a documentação:http://www.mongodb.org/display/DOCS/MapReduce

Além disso, há um passo a passo útil de como uma operação MapReduce funciona na seção "Extras" do artigo do MongoDB Cookbook intitulado "Encontrando valores máximos e mínimos com documentos com versão":http://cookbook.mongodb. org/patterns/finding_max_and_min/

Perdoe-me se você já leu alguns dos documentos referenciados. Eu os incluí para o benefício de outros usuários que podem estar lendo este post e novos no uso do MapReduce no MongoDB

É importante que as saídas das instruções 'emit' nas funções Map correspondam às saídas da função Reduce. Se houver apenas uma saída de documento pela função Mapear, a função Reduzir pode não ser executada e, em seguida, sua coleção de saída terá documentos incompatíveis.

Modifiquei ligeiramente suas instruções map para emitir documentos no formato de sua saída desejada, com dois arrays "classes" separados.
Também reformulei sua instrução reduce para adicionar novas classes aos arrays classes_1 e classes_2, somente se eles ainda não existem.
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'}})

A execução das duas operações MapReduce resulta na seguinte coleção, que corresponde ao formato desejado:
> 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 } }
>

O MapReduce sempre gera documentos na forma de {_id:"id", value:"value"}Há mais informações disponíveis sobre como trabalhar com subdocumentos no documento intitulado "Notação de ponto (alcançar objetos)":http:/ /www.mongodb.org/display/DOCS/Dot+Notation+%28Alcance+into+Objects%29

Se você quiser que a saída do MapReduce apareça em um formato diferente, você terá que fazer isso programaticamente em seu aplicativo.

Esperamos que isso melhore sua compreensão do MapReduce e o aproxime um passo da produção da coleção de saída desejada. Boa sorte!