Laravel使用Eloquent/DB门面或MongoDB查询按group_id取每组首行并分页
方案1:MySQL/PostgreSQL等关系型数据库实现
方法1:Eloquent关联子查询(推荐,性能更优)
假设对应表的模型名为Post,默认按id升序取每个group_id的第一条记录,写法如下:
// 子查询:获取每个group_id对应的最小id(即第一条记录的id) $subQuery = Post::selectRaw('MIN(id) as min_id') ->groupBy('group_id'); // 主查询关联子查询获取完整记录,直接调用paginate实现分页 $records = Post::joinSub($subQuery, 'group_min', function ($join) { $join->on('posts.id', '=', 'group_min.min_id'); }) ->orderBy('posts.id') // 可自定义全局排序规则 ->paginate(10); // 自定义每页展示条数
如果「第一条记录」的判定规则不是id升序,比如按创建时间最早,将子查询的MIN(id)改为MIN(created_at),同步调整关联条件即可。
方法2:DB门面原生查询
逻辑和Eloquent方案一致,用DB门面实现的写法:
$subQuery = DB::table('posts') ->selectRaw('MIN(id) as min_id') ->groupBy('group_id'); $records = DB::table('posts') ->joinSub($subQuery, 'group_min', 'posts.id', '=', 'group_min.min_id') ->orderBy('posts.id') ->paginate(10);
方案2:MongoDB数据库实现(基于jenssegers/laravel-mongodb扩展)
用MongoDB聚合查询实现分组取首条,配合手动生成分页实例:
$pageSize = 10; $currentPage = request('page', 1); // 聚合查询获取当前页数据 $records = Post::raw(function ($collection) use ($pageSize, $currentPage) { return $collection->aggregate([ // 先按分组内排序规则排序,示例为按id升序 ['$sort' => ['_id' => 1]], // 按group_id分组,取每组第一条完整记录 ['$group' => [ '_id' => '$group_id', 'origin_data' => ['$first' => '$$ROOT'] ]], // 展开数据为原表字段结构 ['$replaceRoot' => ['newRoot' => '$origin_data']], // 分页逻辑 ['$skip' => ($currentPage - 1) * $pageSize], ['$limit' => $pageSize] ]); }); // 生成Laravel标准分页实例,支持前端直接调用links()渲染 $total = Post::distinct('group_id')->count(); $records = new \Illuminate\Pagination\LengthAwarePaginator( $records, $total, $pageSize, $currentPage, ['path' => request()->url()] );
内容的提问来源于stack exchange,提问作者Mehdi
相关产品推荐
相关产品推荐

