#laravel #relationship
#laravel #отношения
Вопрос:
Я не понимаю, почему это не работает:
Device::with(['travel.move.position' => function($q) use ($start, $end) {
return $q->whereBetween('created_date', [$start, $end]);
}]);
Я думаю, что это должно дать мне все устройства с travel->move->position
отношениями, но только те, которые position.datetime
находятся между $start
и $end
Я пробовал что-то вроде
Device::whereHas('travel.move.position', function($q) use ($start, $end) {
return $q->whereBetween('created_date', [$start, $end]);
});
и я получаю ожидаемый результат, но я не получаю нетерпеливых отношений.
ДОБАВЛЕН ЗАПРОС ДЛЯ ОТВЕТА 1:
select *
from `devices`
where exists (
select * from `travels`
inner join `travel_info` on `travel_info`.`id` = `travels`.`info_id`
where `devices`.`id` = `travel_info`.`device_id`
and exists (
select *
from `moves`
where `moves`.`travel_id` = `travels`.`id`
and exists (
select * from `positions`
where `moves`.`position_id` = `positions`.`id` and `created_at`
between ? and ?
)
)
Запрос идеален (как и whereHas), но когда выполняется with():
select `travels`.*, `travel_info`.`device_id`
from `travels`
inner join `travel_info` on `travel_info`.`id` = `travels`.`info_id`
where `travel_info`.`device_id` in (?, ?, ?)
....
select * from `moves` where `moves`.`travel_id` in (?, ..., ?)
....
select * from `positions` where `positions`.`id` in (?, ..., ?)
Комментарии:
1. Этот код только фильтрует
position
, а неdevice
. Таким образом, вы все равно получите все устройства, но внутри каждого отношения устройство-> перемещение-> переместить вы увидите только позиции, соответствующие вашему фильтру.2. Ваше поле действительно называется
datetime
? Поскольку это зарезервированное слово в mysql: dev.mysql.com/doc/refman/5.7/en/keywords.html Я думаю, что вам может понадобиться указать этоwhereBetween('
datetime', [$start, $end]);
3. попробуйте добавить
with('travel.move.position')
ко второму запросу. Затем он дает вам ожидаемый результат плюс загруженные отношения.4. @Cyclone . Нет, это испанское слово, которое означает то же самое, но я изменил для лучшего понимания.
5. @kanashin — хаха, хорошо, тогда я понимаю — возможно, вам следует изменить это на что-то другое, например
created_time
и т.д. =)
Ответ №1:
Хорошо, после долгого обсуждения с автором вопроса мы обнаружили, что проблема заключается не в самом запросе, а скорее в неправильной загрузке отношений в with()
инструкции.
Я придумал следующий запрос, который, похоже, возвращает ожидаемый результат. Сначала выполняется основной запрос, чтобы получить все устройства, соответствующие критериям фильтра, а затем применить один и тот же фильтр к каждому из отношений, которые нам нужны для быстрой загрузки:
$start = '2016-10-01';
$end = '2016-10-31';
$devices = Device::whereHas('travel.move.position', function($q) use ($start, $end) {
$q->whereBetween('created_at', [$start, $end]);
})->with([
'travel' => function($q1) use ($start, $end) {
$q1->whereHas('move.position', function($q2) use ($start, $end) {
$q2->whereBetween('created_at', [$start, $end]);
});
},
'travel.move' => function($q1) use ($start, $end) {
$q1->whereHas('position', function($q2) use ($start, $end) {
$q2->whereBetween('created_at', [$start, $end]);
});
},
'travel.move.position' => function($q1) use ($start, $end) {
$q1->whereBetween('created_at', [$start, $end]);
}
])->get();
Комментарии:
1. Спасибо, но это то же самое: я получаю device-> travel-> move-> position-> created_at == ‘2016-09-23’
2. Не могли бы вы включить ведение журнала запросов к базе данных и проверить приведенный выше код в SQL-запросе и опубликовать его в своем вопросе?
3. Может ли один ход иметь несколько позиций?
4. Нет, у него не может быть больше одного. Это отношение принадлежит
5. В добавленных вами SQL-запросах есть две подозрительные вещи: 1.
where moves.position_id = positions.id and created_at ...
почему created_at не имеет префикса к имени таблицы, например,positions.created_at
? 2.select * from positions where positions.id in (?, ..., ?)
неверно. Это должно быть... positions.move_id in (?, ..., ?)