2012-03-14 14 views
18

私はMongoDBでMapReduceを使って簡単な手順を実行しようとしていました。 MapReduceを使用する必要があるかどうか、これが正しいアプローチかどうかはわかりません。私はどのようなキーワードを考え、グーグルは私が最も成功すると思ったところでドキュメントをヒットしようとしましたが、何もありませんでした。たぶん私はこれについてあまりにも難しいと思っていますか? detailsgpasMongoDBで2つのコレクションをマージする

detailsは、文書の全体の束(3+万人)で構成されています

私は2つのコレクションを持っています。

{ "_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} 
... 

gpasdetailsから同じstudentid「sの要素を有する:studentid要素は次のように2回、各yearのための1つを繰り返すことができます。私はこの形式で生徒ごとに1行のコレクションを持つようにしたい最後に

{ "_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} 
... 

{ "_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} 
... 

私はこれを行うつもりだった方法で、このようなstudentidごとに1つだけのエントリ、このようにMapReduceのを実行していた:

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'}}) 

しかし、私はそれを実行すると、これは私の結果のコレクションです:

{ "_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 } } 

クラス配列がありません。

また、結果として得られるMapReduce value要素の要素にアクセスするにはどうすればよいですか? MapReduceは常にvalueに出力されますか?

答えて

41

これは、MongoDBユーザーのGoogleグループで尋ねられた質問に似ています。
https://groups.google.com/group/mongodb-user/browse_thread/thread/60a8b683e2626ada?pli=1

答えはあなたの例のようになりますのオンラインチュートリアル参照:そこに、さらに http://www.mongodb.org/display/DOCS/MapReduce

:MongoDBの中のMapReduceの詳細については http://tebros.com/2011/07/using-mongodb-mapreduce-to-join-2-collections/

を、ドキュメントを参照してください。 MapReduce操作がMongoDB Cookbookの記事「「バージョン付きドキュメントで最大値と最小値を見つける」」の「Extras」セクションでどのように機能するかについての、役に立つステップバイステップのウォークスルーです: http://cookbook.mongodb.org/patterns/finding_max_and_min/

すでに参照文書の一部を読んだことがある場合は、私に許してください。この記事を読んでいる他のユーザーやMongoDBでMapReduceを使っているユーザーの利益のためにそれらを含めました。

Map関数の 'emit'ステートメントの出力がReduce関数の出力と一致することが重要です。 Map関数によって出力されるドキュメントが1つだけの場合、Reduce関数はまったく実行されない可能性があり、出力コレクションに一致しないドキュメントがあります。

2つの別々の「クラス」配列を使用して、目的の出力形式でドキュメントを出力するようにマップ文を少し修正しました。
私はclass文とclass_2配列に新しいクラスを追加するためにreduce文も再作成しました。

> 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は常に{_idの形で文書出力:ご希望の形式と一致し、次のコレクション、二つのMapReduceの操作結果を実行

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'}}) 

"ID" を、値: "値「} 、と題する文書内のサブ文書を扱う上で利用できるより多くの情報があり、 『ドット表記(オブジェクトに到達)』:あなたはMapReduceのトンの出力をご希望の場合 http://www.mongodb.org/display/DOCS/Dot+Notation+%28Reaching+into+Objects%29

は、 o別の形式で表示される場合は、アプリケーションでプログラムで実行する必要があります。

これにより、MapReduceについての理解を深めることができ、望ましい出力コレクションの作成に一歩近づけられることを願っています。がんばろう!

+0

これは非常に助けになりました。私はあなたがこのポストに入れたすべての時間を感謝します。再度、感謝します! – TFX

+0

私の喜び!私は助けてくれることができてうれしいです!心から、マーク – Marc

2

これは1つのコレクションにのみ適用されるように設計されているため、m/rは使用できません。複数のコレクションを読み込むと、シャーディングの互換性が損なわれるため、許可されません。新しいアグリゲーション・フレームワーク(2.1以上)を使用して必要な作業を行うことも、アプリケーション内でこれを行うこともできます。

関連する問題