- カテゴリ: collection
- 掲載バージョン: Laravel 12・PHP 8.4
- 名前空間 / FQCN:
Illuminate\Support\Collection::groupBy - 関連:
countBy/mapToGroups/partition/keyBy/sortBy - 変更履歴: なし
要点(TL;DR)
- 要素を同じキー(または計算結果)ごとにネストしたコレクションへまとめる
- 使い方:
$users->groupBy('team_id') - 罠:
- 既定でキーは再採番(
$preserveKeys=false) - 文字列キーは dot記法(
user.team.id)で辿れ、見つからないとnullグループに入る - 多段グループは
['year', 'status']の順序がそのままネスト順になる
- 既定でキーは再採番(
概要
groupBy は配列/オブジェクトの配列を、指定キー・クロージャ・複数条件で階層的に分類します。Eloquentの取得結果を「月×状態」「部署×職種」などでまとめ、後段で集計・整形に使うのが実務パターンです。クエリビルダの GROUP BY とは別物で、取得後のメモリ内処理です。
構文 / シグネチャ
public function groupBy(string|callable|array $groupBy, bool $preserveKeys = false): Illuminate\Support\Collection
- 引数(表)
| 引数 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
| $groupBy | `string | callable | array` | ✓ |
| $preserveKeys | bool | false | 各グループ内で元のキーを保持するか(false だと0始まりに再採番) |
- 戻り値:
Collection(キー =>Collection)。配列指定時は多重のネストコレクション - 例外/副作用:
- コールバック内での例外はそのまま伝播
- 文字列キーで未定義を辿ると
nullキーにグループ化 LazyCollectionでも使用可だが全件を実体化するためメモリ使用量に注意
使用例
最小例
<?php
use Illuminate\Support\Collection;
$items = collect([
['type' => 'fruit', 'name' => 'apple'],
['type' => 'fruit', 'name' => 'banana'],
['type' => 'vegetable', 'name' => 'carrot'],
]);
$grouped = $items->groupBy('type'); // dot記法も可: 'user.team.id'
print_r($grouped->toArray());
// [
// 'fruit' => [
// ['type' => 'fruit', 'name' => 'apple'],
// ['type' => 'fruit', 'name' => 'banana'],
// ],
// 'vegetable' => [
// ['type' => 'vegetable', 'name' => 'carrot'],
// ],
// ]
実務例:月×ステータスで売上集計
<?php
use Illuminate\Support\Collection;
use Carbon\Carbon;
use App\Models\Order;
// 例: 今月から過去6ヶ月の注文を取得
$orders = Order::query()
->where('created_at', '>=', now()->subMonths(6)->startOfMonth())
->get(['id', 'status', 'amount', 'created_at']);
$grouped = $orders->groupBy([
fn ($o) => $o->created_at->format('Y-m'), // 月
'status', // ステータス
]);
// 各月×ステータスの件数と売上合計を算出
$summary = $grouped->map(fn ($byMonth) => $byMonth->map(function ($ordersByStatus) {
return [
'count' => $ordersByStatus->count(),
'total_amount' => $ordersByStatus->sum('amount'),
];
}));
// 例: 2025-09 の paid 合計
$paidSep = data_get($summary, '2025-09.paid.total_amount', 0);
キー保持(preserveKeys)
$grouped = $items->groupBy('type', preserveKeys: true);
// 各グループ内で、元配列のキーを保持
よくある落とし穴・注意
- キー再採番:
$preserveKeys=falseでは各グループ内が 0,1,2… に再採番。元キーが必要ならtrue。 - 未定義経路の集約:
'user.team.id'が存在しない要素はnullグループに入る。??で補正するならコールバックを使う。 - 多段グループの順序:
['year','status']の順がそのまま ネスト順。アクセスは$groups->get($year)->get($status)。 - LazyCollectionの実体化:全件を保持するため大規模データではメモリ圧迫。必要ならDB側で
GROUP BYし、結果を小さくしてからgroupByする。 - ソートは別:
groupByは並び替えない。並べたい場合はsortKeys()/sortBy()を合わせて使う。
代替・関連APIとの比較
countBy:個数だけ欲しいならこちらが軽量(値→件数)。mapToGroups:コールバックでkey => valueのペア群を返し、1要素を複数のグループに振り分け可能。groupByは1層ごとに1キーへ分類。partition:真偽で 2分割するだけなら簡潔。keyBy:キーを付け替えるだけでグループ化はしない。
コレクション特性(カテゴリ追記)
- チェーン可:可
- 破壊的/非破壊:非破壊(新しい
Collectionを返す) - キー保持:オプション(
$preserveKeys) - LazyCollection:可(ただし全件実体化)
- 計算量の目安:O(n)(nは要素数)
入出力対応(ミニサンプル)
| 入力 | 呼び出し | 出力(概念) |
|---|---|---|
[['t'=>'A'],['t'=>'B'],['t'=>'A']] | ->groupBy('t') | ['A'=>[[…],[…]], 'B'=>[[…]]] |
[['y'=>2025,'s'=>'paid'], …] | ->groupBy(['y','s']) | [2025=>['paid'=>[[…]], 'fail'=>[[…]]]] |
テスト例(Pest)
<?php
use Illuminate\Support\Collection;
it('groups by key and closure', function () {
$c = collect([
['team' => 'A', 'score' => 10],
['team' => 'B', 'score' => 20],
['team' => 'A', 'score' => 30],
]);
$byTeam = $c->groupBy('team');
expect($byTeam->keys())->toEqual(collect(['A','B']));
expect($byTeam['A']->sum('score'))->toBe(40);
$byHighLow = $c->groupBy(fn($x) => $x['score'] >= 20 ? 'high' : 'low');
expect($byHighLow['high']->count())->toBe(2);
expect($byHighLow['low']->count())->toBe(1);
});
トラブルシュート(エラー別)
| 症状/エラー | 原因 | 対処 |
|---|---|---|
Call to a member function format() on null | created_at が null | optional($o->created_at)?->format('Y-m') か nullを別グループに分ける |
| 期待したグループが空 | dot記法のパス違い / キー名誤り | data_get($item, 'path') で確認、またはクロージャで明示 |
| 並びがバラバラ | groupBy はソートしない | ->sortKeys() や ->map(fn($g)=>$g->sortBy('…')) を併用 |
| メモリ不足 | 大量データをすべて保持 | DBで GROUP BY → 少量結果に groupBy、もしくは countBy で代替 |
参考リンク
- Laravel Docs — Collections: groupBy(公式): https://laravel.com/docs/12.x/collections#method-groupby
- ソースコード(Illuminate\Support\Collection): https://github.com/laravel/framework/blob/12.x/src/Illuminate/Support/Collection.php
- ヘルパ
data_get(dot記法): https://laravel.com/docs/12.x/helpers#method-data-get - LazyCollection 概要: https://laravel.com/docs/12.x/collections#lazy-collections

