LaravelのEloquentは、シンプルなデータ操作が可能なORMです。今回は、Eloquentのwhere系メソッドの使い方をケース別にまとめました。
題材として、よくあるブログのデータをサンプルに、where系メソッドの使い方を説明します。
※ 本記事のサンプルはLaravel5.6で動作確認済みです。
目次
テストデータ概要
サンプルとして上記のデータベースを利用します。
記事のデータ(Posts)があり、一人の著者と複数のタグが紐づくデータを想定しています。
記事と著者は1対多、記事とタグは多対多の関係となります。
部分一致
記事のタイトルに対して、あるワードが含まれる記事を検索したいケースなどを想定しています。
Eloquentのwhereを使った実装は下記のようになります。
部分一致で検索したいため、whereの第二引数にLIKE
を設定します。
$title = 'velit';
$posts = Post::where('title', 'LIKE', "%{$title}%")->get();
実際に実行されるSQLは下記のようになります。
select * from `posts` where `title` LIKE %velit%";
複数ワードの部分一致
検索ワードをスペースで区切り、複数のワードが含まれる記事を検索したいケースなどを想定しています。
Eloquentのwhereを使った実装は下記のようになり、where条件をandで繋げます。
$titles = ['velit', 'voluptatibus'];
$posts = Post::where(function ($query) use ($titles) {
foreach ($titles as $title) {
$query->where('title', 'LIKE', "%{$title}%");
}
})
->get();
実際に実行されるSQLは下記のようになります。
select * from `posts` where (`title` LIKE "%velit%" and `title` LIKE "%voluptatibus%");
検索条件のネスト A and (B or C)
A and (B or C) のように検索条件をネストさせます。
例として、あるユーザーの記事 かつ タイトルまたは本文に任意のワードが含まれる記事を取得してみます。
このような場合は、Eloquentのwhereに関数を渡してあげると、where条件をグループ化して設定することができます。
$user = User::inRandomOrder()->first();
$posts = Post::where('author_user_id', $user->id)
->where(function ($query) {
$query
->where('title', 'LIKE', '%ca%')
->orWhere('body', 'LIKE', '%ca%');
})
->get();
実際に実行されるSQLは下記のようになります。
select * from `posts` where `author_user_id` = 3 and (`title` LIKE "%ca%" or `title` LIKE "%ca%");
リレーション先のテーブルでwhere条件設定
リレーションしたテーブルのカラムに対して条件を設定して検索します。
下記のサンプルでは、ユーザー名に一致する記事を取得します。リレーション先のテーブルのカラムに対して条件を設定したい場合は、EloquentのwhereHasを利用します。
$user = User::inRandomOrder()->first();
$posts = Post::with(['user'])
->whereHas('user', function ($query) use ($user) {
$query->where('name', $user->name);
})
->get();
実際に実行されるSQLは下記のようになります。
whereHasを利用すると、サブクエリにより実行されます。
select
*
from
`posts`
where
exists (
select
*
from
`users`
where
`posts`.`author_user_id` = `users`.`id`
and `name` = "三宅 くみ子"
);
複数のタグに関連する記事の取得
最後に、こちらもよくあるケースで、任意の2つのタグの両方に属する記事を取得したいケースです。
同様に、EloquentのwhereHasを利用して実装し、下記のようになります。
$tags = Tag::inRandomOrder()->take(2)->get();
$posts = Post::with(['tags'])
->where(function ($query) use ($tags) {
foreach ($tags as $tag) {
$query->whereHas('tags', function ($query) use ($tag) {
$query->where('tag_id', $tag->id);
});
}
})
->get();
実際に実行されるSQLは下記のようになります。
select
*
from
`posts`
where
(
exists (
select
*
from
`tags`
inner join `post_tag` on `tags`.`id` = `post_tag`.`tag_id`
where
`posts`.`id` = `post_tag`.`post_id`
and `tag_id` = 1
)
and exists (
select
*
from
`tags`
inner join `post_tag` on `tags`.`id` = `post_tag`.`tag_id`
where
`posts`.`id` = `post_tag`.`post_id`
and `tag_id` = 2
)
)
最後に: LaravelのWhereについて
今回のLaravelのwhereの使い方についてまとめると、
- LaravelのEloquentはとても直感的に利用することができる
- whereは関数を渡すこともでき、柔軟に様々な検索条件を設定することができる
- whereHasの条件はサブクエリで発行され、パフォーマンスが出ない可能性はある
となります。
Laravelで実行されたSQLと実行時間は、DBファザードで確認することが出来ますので、処理に時間がかかる場合は実際に実行されるSQLを確認してみると良いと思います。
コメントを残す