web-dev-qa-db-ja.com

Laravel関係テーブル列による雄弁なソート

shop_productsテーブルのpinned列でshop_products_optionsテーブルの製品をソートしようとしました:

$products = Shop\Product::with(['options' => function ($query) {

    $query->orderBy('pinned', 'desc'); 

}])->paginate(5);

Shop\Productモデルでリレーションを設定します。

public function options()
{
    return $this->hasOne('Shop\Options');
}

しかし、製品はソートされていません。 shop_products_optionsテーブルでのみ機能するクエリを取得します。

SELECT * FROM `shop_products_options` WHERE `shop_products_options`.`product_id` in ('8', '9', '10', '11', '12') ORDER BY `pinned` DESC

修正方法

30
alexk

積極的な読み込みでは個別のクエリが使用されるため、このために参加する必要があります。

$products = Shop\Product::join('shop_products_options as po', 'po.product_id', '=', 'products.id')
   ->orderBy('po.pinned', 'desc')
   ->select('products.*')       // just to avoid fetching anything from joined table
   ->with('options')         // if you need options data anyway
   ->paginate(5);

SELECT節は、結合列をProductモデルに追加しないためにあります。


編集:@alexwコメントごと-必要に応じて、結合テーブルの列を含めることができます。それらをselectに追加するか、addSelect/selectRawなどを呼び出すことができます。

68
Jarek Tkaczyk

関連テーブルを手動で結合しないと、関連テーブルの列で並べ替えることはできません。 Jarekの答えは正しいが、これは本当に厄介かもしれない。

1.最初の問題は、選択について心配する必要があるということです。

->select('products.*')

理由:select()なしで、shop_products_optionsのidを選択して、製品モデルにハイドレートできます。

2. 2番目の問題は、groupByについて心配する必要があることです。

->groupBy('products .id');

理由:リレーションがHasOneで、製品に複数のshop_products_optionsがある場合、クエリは製品の行をさらに返します。

3. 3番目の問題は、他のすべてのwhere句を変更する必要があることです:

->where('date', $date)

->where('products .date', $date)

理由:製品とshop_products_optionsは両方とも「日付」属性を持つことができ、その場合、テーブルで属性を選択しないと「あいまいな列」エラーがスローされます。

4. 4番目の問題は、(モデルではなく)テーブル名を使用していることであり、これもまた悪くて厄介です。

->where('products.date', $date)

5. 5番目の問題は、結合されたテーブルのソフト削除について心配する必要があることです。 shop_products_optionsがSoftDeletes特性を使用している場合、以下を追加する必要があります。

->where('shop_products_options .deleted_at', '=', null)

上記の問題はすべて非常にイライラし、テーブルを雄弁に結合するとコードに多くの問題が生じる可能性があります。上記のすべての問題を処理するパッケージを作成しました。関係属性でエレガントな方法でソートできます。

$products = Shop\Product::orderByJoin('options.pinned', 'desc')->paginate(5);

詳細については、 https://github.com/fico7489/laravel-eloquent-join を参照してください

10
fico7489