【发布时间】:2019-07-08 18:46:30
【问题描述】:
我有 2 个表:'Author' 和 'Book',具有以下简单的关系:
class Author extends Model
{
public function books() {
return $this->hasMany('App\Book');
}
}
class Book extends Model
{
public function author() {
return $this->belongsTo('App\Author');
}
}
Book 模型有一个属性price(浮点数)和category(字符串)。
我正在尝试找到一种在 1 个查询中完成这 3 件事的有效方法:
- 从
categorycomedy、created_at在 date1 和 date2 之间获取具有books的所有authors的列表。 -
列表中的作者应该有一个额外的属性
highest_price,这是所有符合步骤 1 条件的作者书籍中的最高价格。 - 图书列表应按
price降序排序,作者的最终结果列表也应按该新属性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)。因为“where”条件必须在两种方法中都有,所以我在 Author 模型上使用了 query scope:
public function scopeWithAndWhereHas($query, $relation, $constraint){
return $query->whereHas($relation, $constraint)
->with([$relation => $constraint]);
}
对于额外的highest_price 属性,我在Collection 上使用了transform() 方法,并结合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 倍!
【问题讨论】:
标签: laravel eloquent query-builder laravel-5.7 laravel-collection