[Laravel] Eloquentのwith関数で、子テーブルの情報をまとめて取得する(Eager Loading)
こんにちは、@yoheiMuneです。
Laravelで実装していて、親テーブル取得時に関連する子テーブルの一覧も合わせて取得したいことがあると思います。そんな時に便利な
ここではコントローラーで記載していますが、記載箇所は任意です。
with関数は、以下のような使い方ができます。
最後になりますが本ブログでは、PHP、フロントエンド、Python、サーバー、インフラ、Swift、Node.js、Java、Linux、機械学習、などの技術トピックを発信をしていきます。「プログラミングで困ったその時の、解決の糸口に!」そんな目標でブログを書き続けています。ぜひ、本ブログのRSSやTwitterをフォローして貰えたら嬉しいです ^ ^
最後までご覧頂きましてありがとうございました!
Laravelで実装していて、親テーブル取得時に関連する子テーブルの一覧も合わせて取得したいことがあると思います。そんな時に便利な
with
関数について、今日はブログを書こうと思います。目次
何がしたいのか
例えば、投稿を表現するposts
テーブルと、その投稿内容(=1〜N枚の画像)を表現するpost_contents
テーブルがあるとします。特定のPostを取得した際に、それにひもづくPostContentsを一覧で取得したい場合に、どうしたら良いかを記載しています。手順1:モデル定義で関連(hasMany)を表現する
まずは、Posts
とPostContents
のモデルを定義し、hasMany
を用いて関連も合わせて定義します。<?php namespace App; use Illuminate\Database\Eloquent\Model; class Post extends Model { // PostContentsへの関連を定義します. public function contents() { return $this->hasMany('App\PostContent'); } }
<?php namespace App; use Illuminate\Database\Eloquent\Model; class PostContent extends Model { }これで、それぞれのモデルと、モデル間の関連を定義できました。
with関数を用いて子テーブルから一覧を取得する
Eloquentのwith
関数を用いて、Postを取得しつつ、合わせて関連するPostContentの一覧も取得します。ここではコントローラーで記載していますが、記載箇所は任意です。
<?php namespace App\Http\Controllers; use App\Post; use App\PostContent; use Illuminate\Http\Request; class PostController extends Controller { public function index() { // withを用いて、関連するPostContentsも一緒に取得する. $post = Post::with('contents')->find(1); return $post; } }これで、Postを取得しつつ、一緒にPostContentの一覧も取得できました。以下のようなJSON形式を取得することができます。
{ "id": 1, "body": "投稿内容です。こんにちは!", "contents": [ { "id": 100, "post_id": 1, "file_url": "https://xxxxxxxx/1bd9.png", }, { "id": 101, "post_id": 1, "file_url": "https://xxxxxxxx/dl1d.png", }, { "id": 102, "post_id": 1, "file_url": "https://xxxxxxxx/okw4.png", } ] }上記のように
contents
というフィールドの中に配列で、PostContentが格納されています。素敵ですね。with関数について詳しく
このwith関数は、Eager Loading という機能で、発行するクエリを少なく、効率的にDBからデータを取得する仕組みです(公式ドキュメントはこちら(英語))。with関数は、以下のような使い方ができます。
// 1つだけ指定(今回紹介したのがこちら). $books = App\Book::with('author')->get(); // 複数指定. $books = App\Book::with(['author', 'publisher'])->get(); // ネストした先も取得. $books = App\Book::with('author.contacts')->get(); // 指定したカラムのみ取得(注意:IDは必ず含める必要がある). $users = App\Book::with('author:id,name')->get(); // 条件指定を追加したい場合. $users = App\User::with(['posts' => function ($query) { $query->where('title', 'like', '%first%'); }])->get(); // ソートしたい場合. $users = App\User::with(['posts' => function ($query) { $query->orderBy('created_at', 'desc'); }])->get();また、上記の場合はコードを実行したら必ず子テーブルも取得しますが、
load
関数を用いると、特定の条件の場合にのみ子テーブルを取得することもできます。// 遅延読み込み. // 特定の条件の場合のみ、Eager Loading を使いたい場合には、「load」関数を利用します. $books = App\Book::all(); if ($someCondition) { $books->load('author', 'publisher'); } // 以前に取得していない場合に限り、Eager Loading を実行する. $book->loadMissing('author');色々と便利ですね〜。もっともっと学んでいきたい今日この頃です。
最後に
Laravelを複数の案件に投入していますが、まだまだ学ぶことが多いです。少しずつブログにアウトプットできたらと思います。最後になりますが本ブログでは、PHP、フロントエンド、Python、サーバー、インフラ、Swift、Node.js、Java、Linux、機械学習、などの技術トピックを発信をしていきます。「プログラミングで困ったその時の、解決の糸口に!」そんな目標でブログを書き続けています。ぜひ、本ブログのRSSやTwitterをフォローして貰えたら嬉しいです ^ ^
最後までご覧頂きましてありがとうございました!