6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Eloquentのwithで指定カラムのみの取得と条件指定を同時にできなかったというお話

Posted at

私が所属している会社の業務でデータの抽出処理を実装するということになったのですが、その抽出条件が多数のテーブルとそのカラムに跨っているという物でした。
その実装方法を色々試している中、「なぜこれができないんだ」と困った話について書いていきたいと思います。

LaravelのEloquentでは、Modelクラス内でリレーションを設定することで、withメソッドを用いて関連するモデルの情報を同時に取得するということができます。

App\SomeData.php
<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class SomeTable extends Model
{
    public function otherData()
    {
        return $this->hasOne('App\OtherData', 'otherdata_id');// hasManyも同様の記述
    }
}
App\SomeTable::with(['otherData']);
// SomeTableのデータと共に、対応するOtherDataのデータも同時に取得できる

この時、OtherDataの内一部のカラムの情報のみが欲しいという場合、そのカラムを記述することで取得するデータを絞ることができます。

App\SomeTable::with(['otherData:otherdata_id,another_column']);
// 対応するOtherDataのデータの内、主キーとanother_columnのみが取得される

また、OtherDataの内特定条件を満たすもののみを取得するということもできます。

App\SomeTable::with([
    'otherData' => function($query) {
        $query->where('another_column', '<', 10);
    }
]);
// 対応するOtherDataのデータの内、another_columnが10未満のもののみが取得される

今回実装したい抽出処理では多数のテーブルに必要な情報が跨っているものの、その内実際に利用するカラムは僅かです。そのため、PHP側での処理が重くならないように次のようなコードを書いてみました。

App\SomeTable::with([
    'otherData:otherdata_id,another_column' => function($query) {
        $query->where('another_column', '<', 10)
    }
]);
// 期待した通りには動かない

改めて考えてみたところ、カラム指定を行わないwithで取得するオブジェクトはModelクラスを継承しているものになっていたのですが、カラム指定をすると単なるCollectionクラスのオブジェクトになっていました。なので、カラム指定をした場合Modelに対するwhereではなく、Collectionに対するwhereとして動作してしまい、期待した動作にはならなかったのではないかと考えています。

今回の抽出処理の実装については、ひとまず愚直にテーブルをjoinすることで実装することにしました。何かいい方法があるとなればコメント等宜しくお願い致します。

6
4
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?