此查询为所有“相册”分页,并为每个相册添加图片和说明。现在我想要总是得到每张专辑的最新图片。
我尝试添加第二个orderBy('pics.created_at')
,但这不起作用。我想我需要某种子查询,但不知道如何。
$query = AlbumPic::select(DB::raw('COUNT(pics.id) as picscount,
pics.url,
pics.user_id,
pics.created_at,
albums.id as album_id,
albums.title,
albums.text,
users.username'))
->join('albums','albums.id','=','album_pic.album_id')
->join('pics','pics.id','=','album_pic.pic_id')
->join('users','users.id','=','pics.user_id');
if(!is_null($user_id))
$query->where('album_pic.user_id',$user_id);
$albums = $query->groupBy('albums.id')
->orderBy('albums.created_at','desc')
->paginate(20);
public function pics()
{
return $this->belongsToMany('Pic');
}
public function latestPic()
{
return $this->belongsToMany('Pic')->latest('pics.created_at');
}
现在查询如下:
$q = Album::with('pics')->with('latestPic.users');
if(!is_null($user_id))
$q->where('albums.user_id',$user_id);
$albums = $q->orderBy('albums.created_at','desc')
->paginate(20);
这很有效。我唯一想改进的是方式,每张专辑的图片都计算在内。现在我使用with('pics')
获取所有内容,然后在视图中执行count($album->pics)
。如果有一种方法不加载所有内容,但只计算图片,那就太好了。
答案 0 :(得分:2)
您需要在子查询中获取MAX(created_at)
;例如,请参阅MySQL select MAX(datetime) not returning max value。
但是,真的,如果你在Laravel中这样做,最好将这些全部设置为关系并利用Eloquent的力量。然后,您可以为使用->latest()
返回最新图片的图片定义关系。有关示例,请参阅laravel eloquent query group by last id(使用一个表,但多个表的原理相同)。
以下是如何使用Eloquent关系进行设置:
用户模型(User.php)
class User extends Eloquent {
public function albums()
{
return $this->hasMany('Album');
}
}
相册模型(Album.php)
class Album extends Eloquent {
public function pics()
{
return $this->belongsToMany('Pic');
}
public function latestPic()
{
return $this->belongsToMany('Pic')->latest('album_pic.created_at');
}
}
由于您在相册和图片之间存在多对多关系,因此在latestPic()
关系中,您必须为album_pic.created_at
指定latest()
字段 - 因为我们实际上对此感兴趣数据透视表中的条目顺序,而不是pics
表中的条目顺序。
最后,将这一切联系起来。例如,对于id
1
的用户:
$albums = User::find(1)->albums()->with('pics')->with('latestPic')->paginate(20);
foreach($albums as $album) {
echo('<br>Album:');
var_dump($album->title);
echo('All pics:');
foreach($album->pics as $pic) {
var_dump($pic->url);
}
echo('Latest pic:');
$latestPic = $album->latestPic->first();
if ($latestPic) {
var_dump($latestPic->url);
}
}
请注意,我们急切地加载pics
和latestPic
以减少对数据库的调用次数。另请注意,访问$latestPic->url
包含在if
语句中,否则没有任何照片的相册会引发错误,因为$album->latestPic
将返回null
。
正如@cedie正确指出的那样,Laravel在使用groupBy
语句时并没有有效地处理分页,但在这种情况下这不应该成为一个问题。基础查询不使用groupBy
,因此您应该保存以使用->paginate(20)
。
答案 1 :(得分:0)
尝试在您的选择查询中使用此功能:
max(pics.created_at) as created_at
而不是:
pics.created_at
所以你的代码应该是这样的:
AlbumPic::select(DB::raw('COUNT(pics.id) as picscount,
pics.url,
pics.user_id,
max(pics.created_at) as created_at,
albums.id as album_id,
albums.title,
albums.text,
users.username'))
答案 2 :(得分:0)
也许你可以弄清楚如何根据你的目的进行调整......
SELECT ap.*
, p.*
FROM album_pic ap
JOIN pics p
ON p.id = ap.pic_id
JOIN
( SELECT ap.*
, MAX(p.created_at) max_created_at
FROM album_pics ap
JOIN p.*
ON p.id = ap.pic_id
) x
ON x.album_id = ap.album_id
AND x.max_created_at = p.created_at;