У меня есть 2 таблицы: ' Автор ' и ' Книга ' со следующими простыми отношениями:
class Author extends Model
{
public function books() {
return $this->hasMany('App\Book');
}
}
class Book extends Model
{
public function author() {
return $this->belongsTo('App\Author');
}
}
Модель книги имеет атрибут price
(float) и category
(string).
Я пытаюсь найти эффективный способ сделать эти 3 вещи в одном запросе:
- получить списоквсе
authors
, которые имеют books
из category
комедии , created_at
между датой 1 и датой 2. - у авторов в списке должен быть дополнительный атрибут
highest_price
, который является самой высокой ценой всех книг автора, которые соответствуют критериям, указанным в шаге 1. - список книг должен быть отсортирован desc по
price
, а список авторов конечных результатов также должен быть отсортирован desc по этому новому атрибуту highest_price
.
Результат должен быть таким:
[
{
id: 1,
name: 'Author ABC'
highest_price: 15
books: [
{
id: 1,
name: 'book1',
category: 'comedy',
price: 15
},
{
id: 2,
name: 'book2',
category: 'comedy',
price: 10
}
]
},
{
id: 10,
name: 'Author XYZ'
highest_price: 12
books: [
{
id: 3,
name: 'book3',
category: 'comedy',
price: 12
}
]
}
]
То, что я получил до сих пор:
Author::with(['books' => function($query) {
$query->where('category', 'comedy')
->where('created_at', '>=', $someFromDate)
->where('created_at', '<=', $someToDate);
}])
->has('books', '>', 0)
->get()
->dd();
Но это только дает мне всех авторов, у которых есть книги, это не учитывает условия в нетерпеливой загрузке ...
Возможно ли это даже в 1 запросе?Буду признателен за любую помощь!
РЕШЕНИЕ
Благодаря ответам я обнаружил, что мне нужно было сочетание with()
и whereHas()
(нашел ответ здесь: https://stackoverflow.com/a/29594039/5297218). Поскольку условия "где" должны быть в обоих методах, я использовал область запроса в модели Author:
public function scopeWithAndWhereHas($query, $relation, $constraint){
return $query->whereHas($relation, $constraint)
->with([$relation => $constraint]);
}
Для дополнительного атрибута highest_price
I 'Мы использовали метод transform()
в коллекции Collection в сочетании с методом max()
для получения максимальной цены. Это конечный результат:
Author::withAndWhereHas('books', function($query) use ($category, $date){
$query->where('category', $category)
->where('created_at', '>=', $date->get('start'))
->where('created_at', '<=', $date->get('end'))
->orderBy('price', 'desc');
})
->get()
->transform(function ($author){
$author['highest_price'] = $author->books->max('price');
return $author;
})
->sortByDesc('highest_price')
->values();
ps: это решениеВ 42 раза больше того, что я делал раньше!