Как отсортировать результаты на основе сводной таблицы в 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();