【初学者向け】Laravel withメソッドの使い方を解説

Laravel

みなさん、こんにちは!

今回は「Laravelのwithメソッドの使い方」を初学者向けで解説していきたいと思います。

withメソッドを使うことで、「N+1問題」を回避しつつ、リレーション先のデータを効率的に取得することができます。データ取得の際に非常によく使われるメソッドなので、Laravelを使う方は必須で押さえておきましょう。

読者
読者

「Laravelのwithメソッドの具体的な使い方は?」

「Laravelのwithメソッドを使うと何がいいの?」

このような疑問をお持ちの方は参考になるかと思います。

それでは、早速見ていきましょう!

withメソッドの使い方

withメソッドを使う場合、リレーションが定義されている必要があります。仮に、以下のようなリレーションが定義されているとしましょう。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Book extends Model
{
    /**
     * その本を書いた著者を取得
     */
    public function author()
    {
        return $this->belongsTo(Author::class);
    }
}

これはAuthorモデルとBookモデルが1対多の関係を示しています。

基本的な使い方

リレーション先のデータを取得する際、リレーション名を使って以下のように取得することができます。

$books = Book::with('author')->get();

withメソッドの引数にはリレーション名を記述します。これにより、本とそれに紐づく著者のデータをセットで取得することができます。

複数リレーションの場合

複数のリレーション先を同時に取得したい場合は、以下のようになります。

$books = Book::with(['author', 'publisher'])->get();

上記の例では、著者と出版社のデータを同時に取得しています。

リレーション先のリレーションを取得する場合

リレーション先のさらにリレーション先を取得するような場合は、ドット構文で取得できます。

$books = Book::with('author.contacts')->get();

上記の例では、本のリレーション先である著者のさらにリレーション先の連絡先データまでを取得しています。3つ以上のリレーション先であっても、基本的にはこのドット構文から取得できます。

リレーション先の取得に条件を追加したい場合

例えば、ユーザーが投稿したポストのうち、タイトルに「コード」が含まれる投稿のみを取得したいような場合は以下のようになります。

use App\Models\User;

$users = User::with(['posts' => function ($query) {
    $query->where('title', 'like', '%コード%');
}])->get();

先ほどと変わらず、ユーザーのリレーション先である投稿データを一緒に取得しているのですが、その投稿データに「タイトルにコードが含まれる」という条件を追加しています。

withメソッドの効果

最後に、なぜリレーション先のデータ取得にwithメソッドを使う方が良いのかについて、軽く触れておきます。

端的にいうと、「N+1問題」が自動的に回避できるという点が大きいかと思います。例えば、以下の処理を見てください。

use App\Models\Book;

$books = Book::all();

foreach ($books as $book) {
    echo $book->author->name;
}

$books = Book::all();この行で全ての本を取得するクエリを1回発行しています。続いて、その下の繰り返し処理内で各本に対する著者データを本の冊数分だけクエリを発行しています。

仮に本の総数が25冊だとすると、全ての本を取得するクエリで1回、各本の著者を取得するクエリが合計25回で総合すると26回分のクエリが発行されていることになります。

一方で、以下の処理を見てください。

$books = Book::with('author')->get();

foreach ($books as $book) {
    echo $book->author->name;
}

こちらがどのようなクエリを発行しているか見てみましょう。

select * from books
select * from authors where id in (1, 2, 3, 4, 5, ...)

なんとたったの2行です。

全ての本を取得するクエリで1回、その本に紐づく著者データを取得するクエリで1回で総数2回分のクエリで済んでいます。

本の冊数がたかだか25冊くらいだと問題ありませんが、例えばこれが100万冊あるとしたらどうでしょうか。withメソッドを使わずに繰り返し処理で取得しようとすると、クエリが約100万回実行されることになります。これだと非常に重たい処理になりますね。

ところが、withメソッドを使うだけで本が何冊だろうとクエリはたったの2回だけです。

これが、withメソッドを使う一番の理由になるかなと思います。

コメント

タイトルとURLをコピーしました