- カテゴリ: collection
- 掲載バージョン: Laravel 12・PHP 8.4
- 名前空間 / FQCN / コマンド:
Illuminate\Support\Collection::whereNotIn - 関連: whereIn / where / whereNotInStrict / filter / reject
- 変更履歴: whereNotInStrict 併存(厳密比較版)
要点(TL;DR)
- 何に使うか:配列/オブジェクトのコレクションから、特定キーの値が「除外リスト」に含まれない要素だけを抽出する
- 最低限の使い方:
$filtered = collect($items)->whereNotIn('status', ['draft','archived']); - よくある罠
- デフォルトは緩い比較(型変換あり)。型を区別したいなら
whereNotInStrictを使う - クエリビルダの
whereNotInと混同しない(こちらはメモリ上のコレクション操作) - 大量件数はパフォーマンスに注意(必要ならDB側で絞り込み)
- デフォルトは緩い比較(型変換あり)。型を区別したいなら
概要
whereNotIn は、与えたキーの値が指定した集合に存在しない要素を残します。Eloquent の結果を受けた後処理や、API レスポンスの整形で「除外リスト」を適用する用途に向きます。whereIn の逆で、厳密比較が必要なら whereNotInStrict を選びます。
構文 / シグネチャ
// Collection
public function whereNotIn(string|int $key, array|\Illuminate\Support\Enumerable $values): static;
// 厳密比較(===)
public function whereNotInStrict(string|int $key, array|\Illuminate\Support\Enumerable $values): static;
引数(表)
| 引数 | 型 | 必須 | 既定値 | 説明 |
|---|---|---|---|---|
$key | `string | int` | ✔ | — |
$values | `array | Enumerable` | ✔ | — |
- 戻り値:
Collection(同型)。条件に一致した要素のみを保持 - 例外/副作用:
- 破壊的でない(元コレクションは変更されない)
$valuesが反復不可能な型だとTypeErrorになり得る
使用例
最小例
<?php
use Illuminate\Support\Collection;
$users = collect([
['id' => 1, 'name' => 'A', 'role' => 'admin'],
['id' => 2, 'name' => 'B', 'role' => 'editor'],
['id' => 3, 'name' => 'C', 'role' => 'viewer'],
['id' => 4, 'name' => 'D', 'role' => 'guest'],
]);
$blocked = ['admin', 'guest'];
$visible = $users->whereNotIn('role', $blocked);
// 結果: role が editor / viewer の要素のみ
実務例(Eloquent結果の後処理)
<?php
use App\Models\Post;
// 例: DBでは公開ステータスで取得し、さらにアプリ側で除外カテゴリを適用
$posts = Post::query()
->where('published', true)
->get();
$hideCategoryIds = [1, 9, 12]; // 例えばユーザー設定やABテストで動的に
$filtered = $posts->whereNotIn('category_id', $hideCategoryIds);
// ドット記法の例:ネストした配列/属性でもOK
$items = collect([
['meta' => ['flag' => 0]],
['meta' => ['flag' => 1]],
['meta' => ['flag' => 2]],
]);
$out = $items->whereNotIn('meta.flag', [0, 2]); // flag が 1 のみ残る
よくある落とし穴・注意
- 比較の厳密さ:
whereNotInは緩い比較(==相当)。'1'と1を区別したい場合はwhereNotInStrictを使用。 - キー保持:
filterベースのため元のキーを保持します。必要に応じてvalues()で連番に整形。 - 大量データ:計算量は概ね O(n)(n=件数、値集合の大きさにも依存)。大量件数のDB結果全件をget→whereNotInは非効率。可能ならクエリビルダ側の
whereNotInで絞る。 - LazyCollection:同名メソッドで遅延評価に対応。ストリーム処理時は LazyCollection を検討。
代替・関連APIとの比較
whereIn:除外ではなく許可リストで残す(逆の意味)。whereNotInStrict:厳密(===)比較。型差が重要ならこちら。where:1値/演算子での条件。複数候補の除外/許可はwhere(In|NotIn)が簡潔。filter/reject:任意ロジックで柔軟。単純な集合除外ならwhereNotInが可読。
チェックポイント(collectionカテゴリの要件)
- チェーン可否:可
- 破壊的/非破壊:非破壊(新しいコレクションを返す)
- キー保持:保持
- LazyCollection:対応
- 計算量の目安:O(n)(n=要素数、除外集合サイズにも一定依存)
入出力対応(小サンプル)
| 入力(role) | 除外集合 | 出力に残る? |
|---|---|---|
admin | ['admin','guest'] | ✗ |
editor | ['admin','guest'] | ✔ |
0 (文字列) | [0] + whereNotIn | ✗(緩い比較) |
0 (文字列) | [0] + whereNotInStrict | ✔(型が異なるため残る) |
テスト例(Pest)
<?php
use Illuminate\Support\Collection;
it('filters items not in the given set', function () {
$items = collect([
['id' => 1, 'status' => 'draft'],
['id' => 2, 'status' => 'published'],
['id' => 3, 'status' => 'archived'],
]);
$out = $items->whereNotIn('status', ['draft', 'archived'])->values();
expect($out->pluck('id')->all())->toBe([2]);
});
it('respects strict comparison when using whereNotInStrict', function () {
$items = collect([
['v' => '0'], // string
['v' => 0], // int
]);
$out = $items->whereNotInStrict('v', [0])->values();
// 厳密比較なので '0' は残り、0 は除外
expect($out->pluck('v')->all())->toBe(['0']);
});
トラブルシュート(エラー別)
| 症状/エラー | 原因 | 対処 |
|---|---|---|
| 期待と違う要素が除外/残存する | 緩い比較により '1' と 1 が同一視 | whereNotInStrict を使用 |
| パフォーマンスが悪い | 大量データをアプリ側で絞っている | DBクエリ段階で whereNotIn を適用、必要列のみ取得 |
| ネストキーで動作しない | キー指定が誤り、または値が存在しない | ドット記法のキーを確認、data_get で値が取れる構造にする |
| 並びが崩れた/キーが飛び番 | filter で元キー保持のため | values() でキーを振り直す |
参考リンク
- Laravel Docs — Collections(
whereIn/whereNotInを含む): https://laravel.com/docs/12.x/collections - Laravel Docs — Lazy Collections: https://laravel.com/docs/12.x/collections#lazy-collections
- API ソース(Illuminate\Support\Collection): https://github.com/laravel/framework/tree/12.x/src/Illuminate/Support
- クエリビルダ
whereNotIn(DB側での絞り込み): https://laravel.com/docs/12.x/queries#where-clauses

