🦀

laravel9¦条件指定をして特定のカラムだけをwithで取得する

2023/03/31に公開

やりたいこと

LaravelのModelクラスでリレーションを定義するとwithで取得できるようになるのですが、リレーション先のカラムをselectして取得したい場合の解決方法を忘れがちなのでまとめました。

  1. リレーション先に条件を指定して取得する
  2. リレーション先のカラムを全て取らずに特定のカラムのみ取得する
  3. リレーション先のリレーション先も特定のカラムのみ取得する

当然ながら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はwithwhereHasを使えばできます。

  • 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