Collectionの中でとても好きなメソッドは、groupBy()です。Laravelが存在しなかった時代ではよくDBクエリから返ってくる1次元の配列をグループ化するため、汚いコードを書いて2次元の配列に変換していたものです。しかし、CollectionのgroupByがあるとコードがシンプルで綺麗に書けること書けること。
このような画面が欲しい
以下のようなデータがDBにあると仮定して、
mysql> select id, name, gender from users; +----+---------------+-----------+ | id | name | gender | +----+---------------+-----------+ | 1 | 山田 千代 | 無回答 | | 2 | 佐藤 健一 | 男 | | 3 | 加藤 篤司 | 無回答 | | 4 | 山口 花子 | 女 | +----+---------------+-----------+ 4 rows in set (0.01 sec)
このデータを性別でグループ化して、以下の画面の表示となるようにしたいのです。

DBレベルでのデータのグループ化
DBレベルでは、データをグループ化して例えば性別(gender)ごとのユーザー数とかを以下のように取得できます。
>>> User::groupBy('gender')->selectRaw('gender, count(*)')->get();
=> Illuminate\Database\Eloquent\Collection {#3422
     all: [
       App\User {#4345
         gender: "女",
         count(*): 1,
       },
       App\User {#4348
         gender: "無回答",
         count(*): 2,
       },
       App\User {#4349
         gender: "男",
         count(*): 1,
       },
     ],
   }
ちなみに実行されたSQL文は、
>>> sql()
=> [
     [
       "query" => "select gender, count(*) from `users` group by `gender`",
       "bindings" => [],
       "time" => 0.56,
     ],
   ]
しかしこれでは先の欲しい画面のデータを表示するには、さらにそれぞれの性別において個々のDBレコードの情報取得が必要となります。つまり、以下のようなSQLの実行が3回必要となります。
>>> User::where('gender', '=', '男')->get();
=> Illuminate\Database\Eloquent\Collection {#4345
     all: [
       App\User {#4348
         id: 2,
         name: "佐藤 健一",
         gender: "男",
...
       },
     ],
   }
しかし、これではトータル4回のSQL文の実行となってしまい効率的でありません。
Collectionでのグループ化
今度は、DBからレコードを全部取得してからデータをグループ化します。
>>> User::all()->groupBy('gender');
=> Illuminate\Database\Eloquent\Collection {#4336
     all: [
       "無回答" => Illuminate\Database\Eloquent\Collection {#4120
         all: [
           App\User {#3392
             id: 1,
             name: "山田 千代",
...
           },
           App\User {#4361
             id: 3,
             name: "加藤 篤司",
 ...
           },
         ],
       },
       "男" => Illuminate\Database\Eloquent\Collection {#4345
         all: [
           App\User {#4188
             id: 2,
             name: "佐藤 健一",
...
           },
         ],
       },
       "女" => Illuminate\Database\Eloquent\Collection {#4276
         all: [
           App\User {#3403
             id: 4,
             name: "山口 花子",
...
           },
         ],
       },
     ],
   }
DBレベルのグループ化と違って、DBから取得した後にCollectionのgroupBy()を適用なので、データをグループ化するだけでなく個々のデータもコレクションにキープしてくれます。そして、実行されたSQL文をチェックしてみると以下のように1つのみです。
>>> sql()
=> [
     [
       "query" => "select * from `users`",
       "bindings" => [],
       "time" => 0.51,
     ],
   ]
コントローラの作成
CollectionのgroupByを使用して必要な構造データを取得できたところで、コントローラを作成です。
namespace App\Http\Controllers;
use App\User;
class UserController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        return view('users')
            ->with(['genders' => User::all()->groupBy('gender')]);
    }
}
ブレードは以下のように、2つのループ(@foreach)を使い、グループのキーである性別と個々のレコードを分けて表示します。
@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">ユーザー性別分け</div>
                <div class="card-body">
                    <table class="table">
                        <thead>
                            <tr>
                                <td class="col-1"></td>
                                <td class="col-1">ID</td>
                                <td>名前</td>
                            </tr>
                        </thead>
                        <tbody>
                        @foreach($genders as $gender => $users)
                            <tr>
                                <td colspan="3">{{ $gender }}</td>
                            </tr>
                            @foreach($users as $user)
                                <tr>
                                    <td></td>
                                    <td class="text-right">{{ $user->id }}</td>
                                    <td>{{ $user->name }}</td>
                                </tr>
                            @endforeach
                        @endforeach
                        </tbody>
                    </table>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection
これでめでたし欲しかった画面の完成です。
メルマガ購読の申し込みはこちらから。