🦀
laravel9¦条件指定をして特定のカラムだけをwithで取得する
やりたいこと
LaravelのModelクラスでリレーションを定義するとwith
で取得できるようになるのですが、リレーション先のカラムをselect
して取得したい場合の解決方法を忘れがちなのでまとめました。
- リレーション先に条件を指定して取得する
- リレーション先のカラムを全て取らずに特定のカラムのみ取得する
- リレーション先のリレーション先も特定のカラムのみ取得する
当然ながらjoin
でもできますし、テーブル設計や取り方を見直すなど他の方法でも解決しますし、もっと簡単かもしれません…
EagerLoad使いたいなということで( '-' )
環境
- Laravel 9
- php 8.1
前提
- companies: ユーザーの所属する会社
- users: ユーザーのテーブル
- posts: ユーザーの投稿内容保存テーブル
各テーブルのModelクラス
User.php
class User extends Model
{
public function company()
{
return $this->belongTo(Company::class);
}
}
Post.php
class Post extends Model
{
public function user()
{
return $this->belongTo(User::class);
}
}
リレーション先のカラムを全て取らずに特定のカラムのみ取得する
やりたいことの1と2はwith
とwhereHas
を使えばできます。
-
with
: リレーション先のテーブルの情報を取得する(Eager Loading) -
wherehas
: リレーション先の条件を加味して取得
Post::with(['user:id,name,status'])
->whereHas('user', function($q) use ($userStatus) {
$q->where('users.status', $userStatus);
})
->get();
with('user')
ではなくwith(['user:id,name,status'])
のようにリレーションメソッド名の後ろに取得したいカラムを指定することで特定のカラムのみ取得できます。
リレーション先のリレーション先のカラムを全て取らずに特定のカラムのみ取得する
やりたいことの3はリレーション先のリレーション先も繋げる場合は.
(ドット記法)を使用するとできるので.
を使いリレーションメソッド名の後ろに取得したいカラムを指定することで特定のカラムのみ取得できます。
$posts = Post::with(['user:id,name,status', 'user.company:id,name'])
->whereHas('user', function($q) use ($userStatus) {
$q->where('users.status', $userStatus);
})
->get();
少し脱線するのですが、取得したデータはアローを繋げて取得すると思うのですが
$post->user->company->id
リレーション先のリレーション先をとる時少し長くなってしまいますよね。
ひとつのアローで取得したい場合はCollectionで操作すると取得できます。
$posts = Post::with(['user:id,name,status', 'user.company:id,name'])
->whereHas('user', function($q) use ($userStatus) {
$q->where('users.status', $userStatus);
})
->get()
->transform(function ($item) {
$item['user_name'] = $item->user->company->name . ' ' . $item->user->name;
return $item;
});
foreach ($posts as $post) {
$post->user_name;
}
withWhereHas
知らない間にwithWhereHas
というハイブリットなものが登場していました。
Laravel 9.16から登場しているようです🔍
ついでに短縮記法が使えるようですね!進化を感じます、、、
YouTube
withWhereHas
で今回のように特定のカラムだけ取れるのかと思って試してみたのですがうまくいかずでした ( ´~` )
時間がある時にコード確認してみたいと思います。
Discussion