Как отсортировать результаты на основе сводной таблицы в Laravel

У меня есть три таблицы, как это:

  • тур (имя) -> предположить (идентификатор:1, имя: что-то)
  • мета (ключ идентификатора) -> предположить (идентификатор:1, ключ: tour_duration)
  • meta_tour (значение meta_id tour_id) -> принять (tour_id:1, meta_id:1, значение: 15)

это много-много отношений.

я хочу отсортировать туры на основе мета-значения в таблице meta_tour следующим образом:

tours orderBy tour_duration.value

Обновить

я попробовал это:

        Tour::with(['metas' => function ($query) {
        $query->where('key', 'tour_duration')
        ->orderByDesc('value');
        }])->paginate(15);

и это:

        Tour::with(['metas' => function ($query) {
        $query->where('key', 'tour_duration');
        }])->orderByDesc('value')->paginate(15);

и это:

        Tour::whereHas('metas' , function ($query) {
        $query->where('key', 'tour_duration')
              ->orderBy('value', 'desc')
        })->paginate(15);

но не работает.

3 ответа

Решение

Вы можете использовать модифицированный withCount():

Tour::withCount(['metas as tour_duration' => function ($query) {
    $query->select('meta_tour.value')->where('key', 'tour_duration');
}])->orderByDesc('tour_duration')->paginate(15);

Это использует подзапрос, чтобы получить value из сводной таблицы:

select `tours`.*,
  (select `meta_tour`.`value`
   from `metas`
   inner join `meta_tour` on `metas`.`id` = `meta_tour`.`meta_id`
   where `tours`.`id` = `meta_tour`.`tour_id`
     and `key` = 'tour_duration') as `tour_duration`
from `tours`
order by `tour_duration` desc

Вы можете использовать withPivot способ заказа по столбцу сводной таблицы:

// Tour model
public function meta () {
    return $this->belongsToMany(Meta::class)
                ->withPivot('meta_tour')
                ->orderByDesc('meta_tour.value');
}

Обновить

Чтобы получить только мету с продолжительностью тура, попробуйте загрузить и добавить в нее предложение where:

$tour->with(['meta' => function ($query) {
    $query->where('key', 'tour_duration');
}])->orderByDesc('meta.value')->get();

Пытаться:

Tour::join('meta_tour', 'meta_tour.tour_id', '=', 'tour.id')
    ->join('meta', 'meta_tour.meta_id', '=', 'meta.id')
    ->where('meta.key', '=', 'tour_duration')
    ->orderBy('meta_tour.value', 'DESC')
    ->get();
Другие вопросы по тегам