Eloquent hasOne 排序依据 分组依据
Eloquent hasOne order by before group by
我有 Album 模型和 AlbumItem 模型 - 代表照片。
在相册模型中我有:
public function first_photo(){
return $this->hasOne('AlbumItem')->orderBy('sort_order', 'asc');
}
在控制器中,我加载了包含第一张照片的相册列表:
Album::with(['first_photo'])->get();
它生成 sql 查询,如下所示:
select * from `album_items`
where `album_items`.`album_id` in (1,2,3,4,5) order by `sort_order` asc
但是 returns 所有具有 album_id = 1,2,3,4,5...
的专辑项目
而且我只需要具有最小值 sort_order
的第一个专辑项目,这就是为什么我尝试使用 GROUP BY 但 ORDER BY 不起作用的原因......即我想更改 first_photo()
方法,以便它会首先 ORDER BY sort_order
,然后 GROUP BY album_id
:
select * from (
select * from `album_items`
where `album_items`.`album_id` in (1,2,3,4,5) order by `sort_order` asc
) temp
group by temp.`album_id`
可以用hasOne
方法得到吗?
好吧,我决定写一个答案..
首先,您应该避免与 non-relation 事物(sort
、order
、group
、where
等)的混乱关系。将其更改为:
public function first_photo(){
return $this->hasOne('AlbumItem');
}
这背后的基本原理是您可以做类似 $model->first_photo()->create([.. relation definition ..])
, or you could $albumItem->Album()->associate([$model])
的事情,甚至可以简单地将 AlbumItem
实例分配给 Album
的 first_photo
关系。
如果你想而且我只需要第一个具有最小值 sort_order 的专辑项目,这就是我尝试使用 的原因,你可以尝试:
Album::with(['first_photo' => function($query){
$query->orderBy('sort_order', 'asc')->first();
}])->get();
编辑:
稍微解释一下 Laravel 如何处理 with()
查询。 Laravel 将首先获取指定的 Album
s,然后继续获取与 Album
s 相关的所有 AlbumItem
s。映射是在没有连接的情况下完成的,但由 PHP 在内存中完成。这在 documentation. However, deep in the Laravel's Eloquent Query Builder, they definitely do relation matching in the PHP - it can be found here and the $relation->match(..)
here, well, it's an abstract, one of it's example is this 中有说明(关于内存部分不是很清楚)。很深,但你应该挖掘框架的一部分..
This loop will execute 1 query to retrieve all of the books on the table, then another query for each book to retrieve the author. So, if we have 25 books, this loop would run 26 queries: 1 for the original book, and 25 additional queries to retrieve the author of each book.
Thankfully, we can use eager loading to reduce this operation to just 2 queries. When querying, you may specify which relationships should be eager loaded using the with method:
public function first_photo(){
return $this->hasOne('AlbumItem')->orderBy('sort_order', 'asc')->limit(1);
}
这将 return 只有一个值。当我们定义关系和预加载时,它总是会触发两个查询。您也可以在此处添加 group by album_id.
Album::with(['first_photo'=> function($q){
return $q->limit(1)->groupBy('album_id');
}])->get();
我有 Album 模型和 AlbumItem 模型 - 代表照片。
在相册模型中我有:
public function first_photo(){
return $this->hasOne('AlbumItem')->orderBy('sort_order', 'asc');
}
在控制器中,我加载了包含第一张照片的相册列表:
Album::with(['first_photo'])->get();
它生成 sql 查询,如下所示:
select * from `album_items`
where `album_items`.`album_id` in (1,2,3,4,5) order by `sort_order` asc
但是 returns 所有具有 album_id = 1,2,3,4,5...
的专辑项目
而且我只需要具有最小值 sort_order
的第一个专辑项目,这就是为什么我尝试使用 GROUP BY 但 ORDER BY 不起作用的原因......即我想更改 first_photo()
方法,以便它会首先 ORDER BY sort_order
,然后 GROUP BY album_id
:
select * from (
select * from `album_items`
where `album_items`.`album_id` in (1,2,3,4,5) order by `sort_order` asc
) temp
group by temp.`album_id`
可以用hasOne
方法得到吗?
好吧,我决定写一个答案..
首先,您应该避免与 non-relation 事物(sort
、order
、group
、where
等)的混乱关系。将其更改为:
public function first_photo(){
return $this->hasOne('AlbumItem');
}
这背后的基本原理是您可以做类似 $model->first_photo()->create([.. relation definition ..])
, or you could $albumItem->Album()->associate([$model])
的事情,甚至可以简单地将 AlbumItem
实例分配给 Album
的 first_photo
关系。
如果你想而且我只需要第一个具有最小值 sort_order 的专辑项目,这就是我尝试使用 的原因,你可以尝试:
Album::with(['first_photo' => function($query){
$query->orderBy('sort_order', 'asc')->first();
}])->get();
编辑:
稍微解释一下 Laravel 如何处理 with()
查询。 Laravel 将首先获取指定的 Album
s,然后继续获取与 Album
s 相关的所有 AlbumItem
s。映射是在没有连接的情况下完成的,但由 PHP 在内存中完成。这在 documentation. However, deep in the Laravel's Eloquent Query Builder, they definitely do relation matching in the PHP - it can be found here and the $relation->match(..)
here, well, it's an abstract, one of it's example is this 中有说明(关于内存部分不是很清楚)。很深,但你应该挖掘框架的一部分..
This loop will execute 1 query to retrieve all of the books on the table, then another query for each book to retrieve the author. So, if we have 25 books, this loop would run 26 queries: 1 for the original book, and 25 additional queries to retrieve the author of each book.
Thankfully, we can use eager loading to reduce this operation to just 2 queries. When querying, you may specify which relationships should be eager loaded using the with method:
public function first_photo(){
return $this->hasOne('AlbumItem')->orderBy('sort_order', 'asc')->limit(1);
}
这将 return 只有一个值。当我们定义关系和预加载时,它总是会触发两个查询。您也可以在此处添加 group by album_id.
Album::with(['first_photo'=> function($q){
return $q->limit(1)->groupBy('album_id');
}])->get();