Laravel Collectionのcount|要素数を数える方法とDBのcountとの違い

by

カテゴリー:

Laravelで「コレクションの要素数を数えたい」ときは、count()メソッドを使えば1行で件数を取得できます。この記事では、Collectionの要素数を数える基本から、条件に合う要素だけを数えるfilter()->count()、値ごとの出現回数を数えるcountBy()、空判定のisEmpty() / isNotEmpty()、さらにCollectionのcount()とデータベース側で集計するQuery Builder・Eloquentのcount()の違いとパフォーマンス差まで整理して解説します。

Collectionのcount()の基本と返り値

countメソッドは、コレクション内の要素の数を整数(int)で返します。引数は不要で、コレクションに含まれる要素の総数をそのまま返します。

$collection = collect([1, 2, 3, 4, 5]);
$count = $collection->count();

echo $count;        // 結果: 5
var_dump($count);   // int(5)

上記の例では、collect関数で配列をコレクションに変換し、countメソッドで要素の数を取得しています。返り値は必ず整数なので、そのまま比較や計算に使えます。空のコレクションに対しては0が返ります。

collect([])->count();   // 0

条件に合う要素だけを数える(filter()->count())

「特定の条件を満たす要素だけ何件あるか」を知りたい場合は、filterで絞り込んでからcountを呼び出します。

$collection = collect([1, 2, 3, 4, 5]);

$count = $collection->filter(function ($item) {
    return $item > 2;
})->count();

echo $count; // 結果: 3

filterメソッドの引数にクロージャ(匿名関数)を渡すと、各要素に対して条件が評価され、trueを返した要素だけが残ります。その結果に対してcountを呼ぶことで「条件に合う件数」を取得できます。連想配列のキーや値で絞り込みたい場合は、whereメソッドでの条件抽出filterメソッドの使い方もあわせて確認してください。

値ごとの出現回数を数える(countBy)と用途の違い

countが「要素の総数」を返すのに対し、countByは「同じ値がそれぞれ何回出現したか」を集計し、値をキー・出現回数を値とした新しいコレクションを返します。

$collection = collect([1, 2, 2, 2, 3]);

$counted = $collection->countBy();

$counted->all();
// [1 => 1, 2 => 3, 3 => 1]

クロージャを渡すと、その戻り値ごとに件数をまとめられます。たとえばメールアドレスのドメインごとの件数を数える、といった集計に便利です。

$emails = collect([
    'alice@gmail.com',
    'bob@gmail.com',
    'carol@example.com',
]);

$counted = $emails->countBy(function ($email) {
    return substr(strrchr($email, '@'), 1);
});

$counted->all();
// ['gmail.com' => 2, 'example.com' => 1]
メソッド返り値主な用途
count()整数要素の総数を数える
filter()->count()整数条件に合う要素だけを数える
countBy()コレクション値ごとの出現回数をまとめて集計する

キーで分類してからそれぞれの件数を扱いたい場合は、groupByでグループ化してから各グループにcount()を適用する方法も使えます。

空かどうかを判定する(isEmpty / isNotEmpty)との使い分け

「件数が0かどうか」だけを知りたいときは、count()の結果を0と比較するよりも、isEmpty() / isNotEmpty()を使うほうが意図が明確です。どちらも真偽値(bool)を返します。

$collection = collect([]);

$collection->isEmpty();     // true(要素が0件)
$collection->isNotEmpty();  // false

// 件数そのものが不要で「あるか / ないか」だけ判定したい場合
if ($collection->isNotEmpty()) {
    // 1件以上あるときの処理
}

使い分けの目安は次のとおりです。実際に件数が必要ならcount()、有無だけを判定するならisEmpty() / isNotEmpty()を使うと、コードの意図が読み取りやすくなります。

やりたいこと推奨メソッド
件数(数値)が必要count()
要素が0件かどうかを判定isEmpty()
要素が1件以上あるかを判定isNotEmpty()

Collectionのcount()とQuery Builder・Eloquentのcount()の違い

同じcount()でも、Collection(PHP側)で数えるのか、Query Builder・Eloquent(データベース側)で数えるのかで、処理の中身は大きく異なります。

// (1) DB側で件数だけを集計する(SELECT COUNT(*) が発行される)
$count = User::where('active', true)->count();

// (2) 全件を取得してからPHP側(Collection)で数える
$count = User::where('active', true)->get()->count();

(1) はEloquent/Query Builderのcount()で、データベースにSELECT COUNT(*)を発行し、件数だけを受け取ります。(2) はget()で全レコードをモデルのCollectionとして取得したあと、PHP側のCollectionのcount()で数えています。結果の数値は同じでも、DBから取得するデータ量とメモリ使用量がまったく違います。

比較項目Query Builder / Eloquent の count()Collection の count()
数える場所データベース側PHP(アプリ)側
発行されるSQLSELECT COUNT(*)全件取得のSELECT *
取得データ量件数のみ(軽い)全レコード(重い)
向いている場面件数だけ必要なとき取得済みデータを再利用するとき

全件取得して数える場合とDB側で集計する場合のパフォーマンス差

件数だけが欲しいのにget()->count()とすると、全レコードをメモリに読み込んでから数えるため、データが多いほど無駄が大きくなります。一方、DB側のcount()SELECT COUNT(*)を1回発行するだけで済み、転送量もメモリ使用量も最小限です。

// △ 件数だけ欲しいのに全件をメモリへ読み込んでいる
$count = Order::all()->count();

// ◎ DB側で集計するので軽い
$count = Order::count();

使い分けの基本は「件数だけ必要ならDB側のcount()」「取得したデータを一覧表示などで再利用する予定があるなら、その取得済みCollectionに対してcount()」です。すでにget()したCollectionを表示に使いつつ件数も出す、といった場面ではCollectionのcount()が有効ですが、件数の取得だけを目的に全件取得するのは避けましょう。

配列・Collection・ページネーション結果での件数取得

件数の取り方はデータの形によって少しずつ異なります。代表的な3パターンを整理します。

// 配列: PHPの count() 関数を使う
$array = [1, 2, 3];
count($array);              // 3

// Collection: count() メソッドを使う
collect($array)->count();   // 3

// ページネーション結果
$users = User::paginate(15);
$users->count();   // 今のページに含まれる件数(最大15)
$users->total();   // 全ページ合計の件数

ページネーション結果で特に注意したいのがcount()total()の違いです。paginate()の戻り値に対するcount()は「現在のページに表示されている件数」を返すのに対し、total()は「絞り込み条件に一致する全件数」を返します。「全部で何件」を出したいときはtotal()を使いましょう。

まとめ

Collectionの要素数を数えるときはcount()が基本で、条件付きならfilter()->count()、値ごとの集計ならcountBy()、有無の判定ならisEmpty() / isNotEmpty()と使い分けます。さらに、件数だけ必要なときは全件取得せずデータベース側のcount()を使うことで、無駄なメモリ消費とクエリ負荷を避けられます。要素の取り出しや加工とあわせて使う場面が多いので、pluckで必要な値を取り出す方法もあわせて押さえておくと、データ操作の幅が広がります。

ホーム » 記事一覧 » 技術メモ » 開発 » Laravelテクニック » Laravel Collectionのcount|要素数を数える方法とDBのcountとの違い

投稿者

ここまで読んでいただき、ありがとうございます。

このサイトでは、私自身が関わっていることや、興味を持って試していることをそのまま置いています。

内容を見ていて、
「少し話を聞いてみたい」
「協業できる部分がありそう」
と感じる点があれば、下記のお問い合わせフォームからご連絡ください。状況を確認したうえで、必要な範囲でお返事します。

特に、以下のWordPressサイトに関する相談にも対応しているのでご興味ありましたらご相談ください。


Comments

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です