タイトル: モデルでselect
SEOタイトル: Laravel Eloquent select (取得) 完全ガイド
| この記事の要点 |
|
Eloquent select の基本パターン
Laravel の Eloquent ORM では、クエリビルダと同じメソッドチェーンで SELECT 系の操作を行います。素の SQL を書かずに、PHP のオブジェクトとして結果を扱えるのが最大の利点です。
use App\Models\User;
// 全件取得 (Collection<User>)
$users = User::all();
// 主キーで 1 件
$user = User::find(1); // 無ければ null
$user = User::findOrFail(1); // 無ければ ModelNotFoundException (404)
// 条件付き 1 件
$user = User::where('email', $email)->first(); // 無ければ null
$user = User::where('email', $email)->firstOrFail();// 無ければ例外
// 条件付き複数件
$users = User::where('status', 'active')
->orderBy('created_at', 'desc')
->limit(20)
->get();
// 件数
$count = User::where('status', 'active')->count();
// 存在チェック (count(*) より速い)
if (User::where('email', $email)->exists()) { ... }
取得メソッドの一覧
| メソッド | 戻り値 | 用途 |
|---|---|---|
all() | Collection | 全件 (テーブル小さい時のみ) |
get() | Collection | クエリ結果の全件 |
first() | Model or null | 1 件目、無ければ null |
firstOrFail() | Model | 1 件目、無ければ 404 |
find($id) | Model or null | 主キー検索 |
findOrFail($id) | Model | 主キー検索 (例外) |
findMany([1,2,3]) | Collection | 複数主キーをまとめて |
value('name') | scalar | 1 カラムだけ取得 |
pluck('name') | Collection | 1 カラムを配列状に |
count() / sum() / avg() | 数値 | 集約関数 |
exists() / doesntExist() | bool | 存在チェック |
カラム指定 select
デフォルトでは SELECT * になります。不要なカラムを取らないことでメモリと転送量を削減できます。
// 取得時に指定
$users = User::select(['id', 'name', 'email'])->get();
// 生 SQL の SELECT 句として
$users = User::select(['id', DB::raw('COUNT(*) as cnt')])
->groupBy('id')
->get();
// addSelect で追加
$users = User::select('id')->addSelect('name')->get();
// $hidden / $visible でモデル側に指定
class User extends Model
{
protected $hidden = ['password', 'remember_token'];
// または逆指定
protected $visible = ['id', 'name', 'email'];
}
where / orderBy / limit / paginate
// 基本
$users = User::where('age', '>=', 20)
->where('status', 'active')
->orWhere('role', 'admin')
->orderBy('created_at', 'desc')
->limit(10)
->offset(20)
->get();
// where のいろいろ
User::whereIn('id', [1, 2, 3])->get();
User::whereNotIn('status', ['banned'])->get();
User::whereBetween('age', [20, 30])->get();
User::whereNull('deleted_at')->get();
User::whereNotNull('email_verified_at')->get();
User::whereDate('created_at', '2026-01-01')->get();
User::whereYear('created_at', 2026)->get();
// クロージャでグループ化
User::where('status', 'active')
->where(function ($q) {
$q->where('role', 'admin')->orWhere('role', 'editor');
})
->get();
// ページング
$users = User::orderBy('id')->paginate(15); // ?page=2 で取得
$users = User::orderBy('id')->simplePaginate(15); // 件数表示なし、軽量
$users = User::orderBy('id')->cursorPaginate(15); // Seek 方式、大量データ対応
リレーション + Eager Loading (N+1 対策)
Eloquent 最大のハマりどころは N+1 問題です。リレーションを ->with() で事前ロードすることで解決します。
// ❌ N+1: ユーザーごとに posts クエリが発行される
$users = User::all();
foreach ($users as $user) {
echo $user->posts->count(); // ← 毎回 SELECT
}
// ✅ Eager Loading: 2 クエリで済む
$users = User::with('posts')->get();
foreach ($users as $user) {
echo $user->posts->count(); // ← 追加クエリなし
}
// ネスト
$users = User::with('posts.comments.user')->get();
// 複数リレーション
$users = User::with(['posts', 'profile', 'roles'])->get();
// リレーションにも条件
$users = User::with(['posts' => function ($q) {
$q->where('published', true)->orderBy('created_at', 'desc')->limit(5);
}])->get();
// 件数だけ取得 (withCount)
$users = User::withCount('posts')->get();
// → $user->posts_count で参照
whereHas / whereDoesntHave
リレーション先の条件で親レコードを絞り込むパターン:
// 投稿が 5 件以上あるユーザー
$users = User::whereHas('posts', function ($q) {
$q->where('published', true);
}, '>=', 5)->get();
// 投稿が 1 件もないユーザー
$users = User::whereDoesntHave('posts')->get();
// withWhereHas (Laravel 9+): 条件付き取得 + Eager Load を同時に
$users = User::withWhereHas('posts', function ($q) {
$q->where('published', true);
})->get();
大量データの取得: chunk / cursor
get() や all() はメモリに全件ロードします。10 万件以上なら chunk / cursor を必ず使います。
// chunk: 100 件ずつ取得して処理
User::orderBy('id')->chunk(100, function ($users) {
foreach ($users as $user) {
// ...
}
});
// chunkById: chunk より安全 (更新時に取りこぼし無し)
User::chunkById(100, function ($users) {
foreach ($users as $user) {
$user->update(['flag' => 1]);
}
});
// cursor: 1 件ずつジェネレータで取得 (PHP 側のメモリ最小)
foreach (User::where('active', 1)->cursor() as $user) {
// 1 件ずつ処理
}
// lazy (Laravel 8+): chunk + cursor のハイブリッド
User::where('active', 1)->lazy(500)->each(function ($user) {
// ...
});
生 SQL と DB::raw
use Illuminate\Support\Facades\DB;
// 生のカラム式
$users = User::select(DB::raw('COUNT(*) as cnt, role'))
->groupBy('role')
->get();
// whereRaw
$users = User::whereRaw('YEAR(created_at) = ?', [2026])->get();
// orderByRaw
$users = User::orderByRaw('FIELD(status, ?, ?, ?)', ['admin', 'editor', 'viewer'])->get();
// 完全な生 SQL
$users = DB::select('select * from users where id = ?', [1]);
// 結果は stdClass の配列、Eloquent モデルではない
クエリログでデバッグ
DB::enableQueryLog();
$users = User::with('posts')->where('active', 1)->get();
dd(DB::getQueryLog());
// または toSql() / toRawSql() (Laravel 10.15+)
$sql = User::where('active', 1)->toSql();
// → select * from `users` where `active` = ?
// dd() / dump() でその場で確認
User::where('active', 1)->dd(); // SQL を吐いて die
User::where('active', 1)->dump(); // SQL を吐いて続行
FAQ
Q: all() と get() の違い
A: all() は条件なし全件、get() はクエリビルダのチェーンの結果。where()->all() はエラー、where()->get() が正解。
Q: 取得結果を配列にしたい
A: User::all()->toArray() または ->pluck()。素の配列にしたい場合は DB::table('users')->get()->toArray()。
Q: Collection と LazyCollection の違いは?
A: 通常の get() は Collection (全件メモリ)、cursor() / lazy() は LazyCollection (ジェネレータ)。大量データなら必ず後者。