Here's my code to do an equivalent of a GROUP BY and a SUM
<?php
$contributionCol = $db->customers->contribution;
$group = $contributionCol->group(array('date' => true), array('sum' => 0), "function (obj, prev) { prev['sum'] += obj.amount; }");
?>
This groups by the 'date' column and sums over the 'amount' column. In my testing this was much slower than querying all rows and doing the Group by code with PHP. It could just be my particular setup and data set.
Also at first my amount column was a string, which caused the results to be concatenated rather than arithmetic addition, something else to watch out for.
MongoCollection::group
(PECL mongo >=0.9.2)
MongoCollection::group — SQL の GROUP BY コマンドと似た処理を行う
説明
パラメータ
-
keys -
group by したいフィールド。 配列あるいは非コードオブジェクトが渡された場合は、 結果をグループ化するキーとして扱います。
1.0.4+:
keysが MongoCode のインスタンスである場合は、keysはグループ化のキーを返す関数であると見なします (下の例 "keysへ関数を渡す" を参照ください)。 -
initial -
集約カウンタオブジェクトの初期値。
-
reduce -
ふたつの引数 (現在のドキュメント、 そして集約する点) を受け取って集約をする関数。
-
options -
group コマンドへのオプションのパラメータ。次のオプションが使えます。
-
"condition"
集約処理に含めるドキュメントの条件。
-
"finalize"
一意なキーごとに一度だけコールされる関数。 reduce 関数の最後の出力を受け取ります。
-
返り値
結果を含む配列を返します。
例
例1 MongoCollection::group() の例
これは、ドキュメントをカテゴリー別にまとめて カテゴリーごとの名前の一覧を作ります。
<?php
$collection->insert(array("category" => "fruit", "name" => "apple"));
$collection->insert(array("category" => "fruit", "name" => "peach"));
$collection->insert(array("category" => "fruit", "name" => "banana"));
$collection->insert(array("category" => "veggie", "name" => "corn"));
$collection->insert(array("category" => "veggie", "name" => "broccoli"));
$keys = array("category" => 1);
$initial = array("items" => array());
$reduce = "function (obj, prev) { prev.items.push(obj.name); }";
$g = $collection->group($keys, $initial, $reduce);
echo json_encode($g['retval']);
?>
上の例の出力は、 たとえば以下のようになります。
[{"category":"fruit","items":["apple","peach","banana"]},{"category":"veggie","items":["corn","broccoli"]}]
例2 MongoCollection::group() の例
この例ではキーを使わないので、すべてのドキュメントがそれ自身のグループに属します。 また、この例では条件を使います。 この条件にマッチするドキュメントのみがグループ関数による処理の対象となります。
<?php
$collection->save(array("a" => 2));
$collection->save(array("b" => 5));
$collection->save(array("a" => 1));
// すべてのフィールドを使用します
$keys = array();
// 初期値を設定します
$initial = array("count" => 0);
// 実行する JavaScript 関数
$reduce = "function (obj, prev) { prev.count++; }";
// "a" フィールドが 1 より大きいドキュメントのみを使用します
$condition = array("a" => array( '$gt' => 1));
$g = $collection->group($keys, $initial, $reduce, $condition);
var_dump($g);
?>
上の例の出力は、 たとえば以下のようになります。
array(4) {
["retval"]=>
array(1) {
[0]=>
array(1) {
["count"]=>
float(1)
}
}
["count"]=>
float(1)
["keys"]=>
int(1)
["ok"]=>
float(1)
}
例3 keys へ関数を渡す
フィールド名以外の何かでグループ化したい場合は、 MongoCollection::group() の最初のパラメータに関数を渡すと 各ドキュメントに対してそれを実行します。 関数の返り値を使ってグループ化することができます。
この例は、num フィールドを 4 で割ったあまりでグループ化する方法を示すものです。
<?php
$c->group(new MongoCode('function(doc) { return {mod : doc.num % 4}; }'),
array("count" => 0),
new MongoCode('function(current, total) { total.count++; }'));
?>
Here I am posting how I get tags from my documents. Documents should have 'tags' field which is array of strings:
{'tags':['php', 'mongo']}
<?php
$keys = array();
$initial = array('tags'=>array(), 'count'=>0);
$reduce = 'function (doc, total) { if (doc.tags.length) {doc.tags.forEach(function (e) {total.tags[e]=total.tags[e]||0; total.tags[e]++; total.count++;});} }';
$criteria = array(
'condition' => array(
'tags' => array('$exists'=>true)
),
);
?>
