Laravel – 子テーブルの条件で絞り込み

概要

複数テーブルが関連付けられているデータを子テーブルの条件で絞り込みたい場合。クエリービルダーJOIN句によってテーブルを結合すると結果は配列となるが、配列ではなくオブジェクトのままリレーションで操作したいとき。

whereHas()メソッドを使うと、親のモデルでhasMany()で定義された子モデルの操作が可能になる。

whereHas()の使い方は以下のとおり。

  • 第1引数で子モデル名を指定
  • 第2引数にクエリーを引数としたコールバックを定義
    • コールバックで引数のクエリーに対してクエリービルダーメソッドを適用
  • 最後のget()を忘れがちなので注意

準備

クエリービルダーの確認で使ったテーブルで確認する。

1つ先のリレーション

親が直接持つ子モデルの場合、以下の様に記述する。ここでは子モデルのcustomerの名前が'customer2'のデータを抽出している。

抽出結果は親モデルのコレクションとしてビューに渡している。

モデルのコレクションを受け取ったビューでは、親モデルとしてこれらを扱い、必要に応じてリレーションによって子モデルの属性を取り出す。

emailを持たないcustomerに対応するため、optional()メソッドを使っている

結果は以下のとおりで、customer.id=2に相当するcustomer2のデータが抽出されている。

  1. 2020-06-05 00:00:00: customer2
    • e-mail: customer2@mail.com
    • item: rubber sheet
  2. 2020-06-06 00:00:00: customer2
    • e-mail: customer2@mail.com
    • item: plastic plate

 

whereHas()で生成されるSQLを確認しておく。where句の対象としてサブクエリーが構成されている(見やすいように結果を改行している)。

バインドされる値も確認。

2つ先のリレーション

子モデルの子モデルの属性で絞り込む場合は、whereHas()のコールバック内でwhereHas()を入れ子で呼び出す。呼び出し部分だけを取り出すと以下のとおり。

コールバックの引数は、コールバック内ローカルスコープなので同じ名前でも構わない。

結果は以下のとおりで、メールアドレスが'customer2'で始まるcustomer2のみ取り出されている。

  1. 2020-06-05 00:00:00: customer2
    • e-mail: customer2@mail.com
    • item: rubber sheet
  2. 2020-06-06 00:00:00: customer2
    • e-mail: customer2@mail.com
    • item: plastic plate

 

生成されるSQLを確認。サブクエリーが入れ子で構成されている。

バインドされる値も確認。

 

1件のコメント

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です