Laravel分组Eloquent集合:如何获取每组精确3条视频数据
解决Laravel分组后每个分类取N条数据的问题
嘿,我完全懂你的困扰——直接在查询末尾加take(3)只会把整个结果集限制到3条,根本不是你想要的每个分类组里取3条视频。这里有两个实用的解决方案,你可以根据自己的场景选:
方法一:利用Collection的map处理分组后的数据
这是最直接的方式,既然你已经通过groupBy得到了按分类分组的集合,只需要遍历每个分组,对每个分组内的视频集合调用take(3)就行:
private function getHomePageVideos($lang = 'en') { return \DB::table('videos') ->leftJoin('categories', 'categories.id','=','videos.category_id') ->select('videos.*', 'categories.title_' . $lang . ' as category', 'categories.slug as category_slug') ->get() ->groupBy('category') // 遍历每个分类组,只保留每组的前3条视频 ->map(fn($group) => $group->take(3)); }
这个方法的优点是代码简单易读,适合数据量不大的场景,不需要改动底层查询逻辑。
方法二:数据库层面用窗口函数过滤(更高效)
如果你的视频数据量很大,先把所有数据查出来再处理会浪费内存,这时候可以用数据库的窗口函数(MySQL 8.0+、PostgreSQL等支持),在查询阶段就直接筛选出每个分类的前3条数据:
private function getHomePageVideos($lang = 'en') { return \DB::table(function ($query) use ($lang) { $query->from('videos') ->leftJoin('categories', 'categories.id', '=', 'videos.category_id') ->select( 'videos.*', 'categories.title_' . $lang . ' as category', 'categories.slug as category_slug', // 按category_id分组,给每个分类下的视频编号(这里按id倒序,你可以改成自己的排序规则) \DB::raw('ROW_NUMBER() OVER (PARTITION BY videos.category_id ORDER BY videos.id DESC) as row_num') ); }, 'ranked_videos') // 只保留每个分类的前3条 ->where('row_num', '<=', 3) ->get() ->groupBy('category'); }
这里用ROW_NUMBER()窗口函数给每个分类下的视频按指定顺序(比如id倒序,也就是最新的在前)编号,然后只取编号≤3的记录,最后再分组。这种方式能大幅减少数据库返回的数据量,性能更好。
你可以根据自己的数据库版本和数据规模选择合适的方法,试试吧!
内容的提问来源于stack exchange,提问作者Tigran.S
相关产品推荐
相关产品推荐

