2012-08-31 17 views
11

私は非常に簡単だと思うことをしようとしています。 mongoに共通のキーと属性の可変数を持つ一連のレコードがあるとします。私はすべての属性を選択し、レコード間で名前でグループ化したいと思います。例* group by mongo aggregationを選択してください

{ Name: George, x: 5, y: 3 } 
{ Name: George, z: 9 } 
{ Name: Rob, x: 12, y: 2 } 

のために私はこのようになりますそのCSVを作成したいと思います:

Name  X Y Z 
George 5 3 9 
Rob  12 2 

は、残念ながら、私はすべてのレコードのような名前ではなく、の労働組合を取り戻す

DB.data.aggregate({ $group : { _id : "$Name" } }) 

を試してみましたすべての可能な属性。

答えて

11

アトリビュートを組み合わせたい場合は、アトリビュートをgroupに追加する必要があります。

db.data.aggregate(
    { $group : { 
      _id : "$Name", 
      x: { $addToSet: "$x" }, 
      y: { $addToSet: "$y" }, 
      z: { $addToSet: "$z" }, 
    }} 
) 

戻り値:たとえば、それぞれの名前でグループ化されたX、Y、Zの属性の一意の値を見つけるために$addToSetを使用してここで

{ 
    "result" : [ 
     { 
      "_id" : "Rob", 
      "x" : [ 
       12 
      ], 
      "y" : [ 
       2 
      ], 
      "z" : [ ] 
     }, 
     { 
      "_id" : "George", 
      "x" : [ 
       5 
      ], 
      "y" : [ 
       3 
      ], 
      "z" : [ 
       9 
      ] 
     } 
    ], 
    "ok" : 1 
} 
+0

ありがとう、私は$ pushを使用して同様のことを行い、それは動作するようです。私のフォローアップの質問は、結果セット内の内部配列を解凍して、データをフラットCSVにエクスポートすることが最善の方法であるかどうかです。 –

+0

私はcsvを作成するためにpymongoとpythonを使用しています。残りの1つの問題は、私が$ addToSetを使用するときに、各キー値の対に対して1つの別個の値があっても、各キーの結果の配列を作成していることです。これにより、csvへのフラット化のプロセスが非常に面倒になります。キー値の配列を作成しないようにする方法はありますか? –

+1

@RogerSanchez: '$ addToSet'や' $ push'は配列の値を返しますので、CSVエクスポートでいくつかのマッサージを行うか、別の集計関数を考慮する必要があります。たとえば、すべての値が数値で、フィールドごとに一意の値が1つしかない場合は、['$ max'](http://docs.mongodb.org/manual/reference/aggregation/)を使用して取り除くことができます。 #_S_max)を使用してください。結果の値が*時には*配列の場合は、コード内で争う必要があります。以下は、役に立つかもしれないPython要点の例です:[CSVでの配列のアラインメントの平坦化](https://gist.github.com/a39b087da394b746e4fe)。 – Stennie

0

は、それを行うための別の方法である:

$connection = 'mongodb://localhost:27017'; 
$con  = new Mongo($connection); // mongo connection 

$db   = $con->test; /// database 
$collection = $db->prb; // table 

$keys  = array("Name" => 1,"x"=>1,"y"=>1,"z"=>1); 

// set intial values 
$initial = array("count" => 0); 

// JavaScript function to perform 
$reduce  = "function (obj, prev) { prev.count++; }"; 

$g   = $collection->group($keys, $initial, $reduce); 

echo "<pre>"; 
print_r($g); 

あなたは答えのようなもの(ない正確な出力)を取得します:

をグループへ
Array 
(
    [retval] => Array 
     (
      [0] => Array 
       (
        [Name] => George 
        [x] => 
        [y] => 
        [z] => 
        [count] => 2 
       ) 

      [1] => Array 
       (
        [Name] => Rob 
        [x] => 
        [y] => 
        [z] => 
        [count] => 1 
       ) 

     ) 

    [count] => 5 
    [keys] => 3 
    [ok] => 1 
) 
+1

あなたのコレクションが断片化されていない限り、 'group'は実行可能なオプションですが、 PHP以外の質問でPHPの例を使用しないでください。 – JohnnyHK

+1

@ JohnnyHK:私は長い間それを探していましたが、私はこのリンクをスタックに持っていましたが、それは私に適切な答えを与えてくれなかったので、答えを見つけたらここに投稿しました。本当に私は私がそれを行うことができます削除することができます。 –

+0

までですが、 'aggregate'はこの場合より優れた解決策であり、可能であればJavaScriptは 'ネイティブ'のmongo言語であるべきです。心配しなくても、あなたに知らせるだけです。 – JohnnyHK

-1

使用$addToSet、それは

db.data.aggregate(
    { $group : { 
      _id : "$Name", 
      x: { $addToSet: "$x" }, 
      y: { $addToSet: "$y" }, 
      z: { $addToSet: "$z" }, 
    }} 
) 
0

に動作しますStennieからのソリューションは、あなたが照会しているコレクション内の各一致する項目から復帰したい属性を正確に把握する必要があります。これは必ずしもそうではありません。

私たちが書いているGrailsアプリケーションのGroovyでこの問題を解決しなければなりませんでした。

私たちは、このような方法で処理するために書いたリクエスト「Xで見つける」:

private List<DBObject> findDistinctPages(Map by) { 
    def command = 
     new GroupCommand(
       (DBCollection) db.pages, 
       new BasicDBObject(['url': 1]), 
       new BasicDBObject(by), 
       new BasicDBObject([:]), 
       'function (current, result) { for(i in current) { result[i] = current[i] } }', 
       '' 
     ) 
    db.pages.group(command).sort { it.title } 
} 

をそして次のように私たちのコード内でそれを呼び出す:これは動作します

def pages = findDistinctPages([$or: [[type: 'channel'], [type: 'main']]]) 

を結果を渡すことで、 GroupCommandの最後にあるjavascript関数への最初のクエリのMongoは、最初のクエリで指定した属性だけを返します。それ以外の場合は、2回目の結果を繰り返して、残りのデータをmongoから取得しなければなりません。

関連する問題