MongoCollection::group

(PECL mongo >=0.9.2)

MongoCollection::groupSQL の GROUP BY コマンドと似た処理を行う

説明

public MongoCollection::group ( mixed $keys , array $initial , MongoCode $reduce [, array $options = array() ] ) : array

パラメータ

keys

group by したいフィールド。 配列あるいは非コードオブジェクトが渡された場合は、 結果をグループ化するキーとして扱います。

1.0.4+: keysMongoCode のインスタンスである場合は、 keys はグループ化のキーを返す関数であると見なします (下の例 "keys へ関数を渡す" を参照ください)。

initial

集約カウンタオブジェクトの初期値。

reduce

ふたつの引数 (現在のドキュメント、 そして集約する点) を受け取って集約をする関数。

options

group コマンドへのオプションのパラメータ。次のオプションが使えます。

  • "condition"

    集約処理に含めるドキュメントの条件。

  • "finalize"

    一意なキーごとに一度だけコールされる関数。 reduce 関数の最後の出力を受け取ります。

  • "maxTimeMS"

    サーバー上で操作を行う累積時間の制限 (アイドル時間を含まない) を、ミリ秒単位で指定します。この時間内にサーバー側の操作が完了しなければ、MongoExecutionTimeoutException をスローします。

返り値

結果を含む配列を返します。

変更履歴

バージョン 説明
1.5.0 "maxTimeMS" オプションが追加されました。
1.2.11 optionsscalar のときに E_DEPRECATED を発行するようになりました。

例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('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++; }'));

?>
add a note add a note

User Contributed Notes 4 notes

up
2
nick at pitchinteractive dot com
12 years ago
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.

[red.: Instead of this, please use the new aggregation framework. See the documentation for MongoCollection::aggregate]
up
0
ury dot zend at gmail dot com
9 years ago
quoting Evgeniy Abduzhapparov example for correction, since is not working on newest php mongo driver version

instead of use:
<?php
$initial
= array('tags'=>array(), 'count'=>0);
?>
for var tags,
you have to cast the empty array to an object or use new stdClass()
<?php
$initial
= array('tags'=> (object) array(), 'count'=>0);

$initial = array('tags'=> new stdClass(), 'count'=>0);
?>
up
-1
ronan dot guilloux at gmail dot com
12 years ago
Since the $options argument is no longer a scalar (deprecated since the 1.2.11 version of the Mongo's PHP driver), you now must compose your $options as an associative array, otherwise you'll rise a "Implicitly passing condition as $options will be removed in the future" alert.

Example:

<?php

$m
= new Mongo();
$db = $m->selectDB('test');
$collection = new MongoCollection($db, 'FooBar');

// grouping results by categories, where foo is 'bar'
$keys = array('categorie'=>true, 'foo'=>true); // the fields list we want to return
$initial = array('count' => 0); // gets a subtotal for each categorie
$reduce = "function(obj,prev) { prev.count += 1; }"; // yes, this is js code
$conditions = array('foo'=> 'bar');
$grouped = $myColl::group($keys, $initial, $reduce, array('condition'=>$conditions));
$result = $grouped['retval'];

?>
up
-3
Evgeniy Abduzhapparov
14 years ago
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)
    ),
);
?>
To Top