Laravel ORM如何获取每个分类下的最新10篇关联文章?
解决Laravel中每个分类获取最新10篇文章的问题
问题原因
你使用的with(['posts' => function($q) { $q->take(10); }])写法存在逻辑问题:Laravel的预加载机制会先查询所有分类,再执行一条关联查询获取所有关联的posts,此时take(10)是限制所有分类的posts总条数,而非每个分类单独取10条,因此出现了各分类posts数量之和为10的结果。
解决方案
方法一:子查询筛选每个分类的最新10篇(推荐,兼容大多数数据库版本)
通过子查询获取每个分类下最新10篇文章的ID,再关联查询这些文章:
$categories = Category::query() ->with(['posts' => function ($query) { $query->whereIn('id', function ($subQuery) { $subQuery->select('id') ->from('posts') ->whereColumn('posts.category_id', 'categories.id') ->latest() // 按创建时间倒序,取最新的 ->take(10); })->latest(); // 保持文章的排序 }]) ->get();
方法二:遍历分类单独查询(简单直观,适合分类数量少的场景)
先获取所有分类,再逐个查询每个分类的最新10篇文章,会产生N+1次查询(N为分类数量):
$categories = Category::all(); $categories->each(function ($category) { $category->setRelation('posts', $category->posts()->latest()->take(10)->get()); });
方法三:使用窗口函数(MySQL 8.0+/PostgreSQL等支持窗口函数的数据库)
利用窗口函数RANK()按分类分组并排序,筛选出每个分类前10的文章:
// 先获取符合条件的所有文章 $qualifiedPosts = Post::query() ->selectRaw('posts.*, RANK() OVER (PARTITION BY category_id ORDER BY created_at DESC) as post_rank') ->having('post_rank', '<=', 10) ->get(); // 关联到分类上 $categories = Category::query() ->with(['posts' => function ($query) use ($qualifiedPosts) { $query->whereIn('id', $qualifiedPosts->pluck('id'))->latest(); }]) ->get();
补充说明
如果需要频繁使用这个逻辑,可以将其封装为Category模型的一个关联方法,方便复用:
// Category模型 public function latestPosts() { return $this->hasMany(Post::class) ->whereIn('id', function ($subQuery) { $subQuery->select('id') ->from('posts') ->whereColumn('posts.category_id', 'categories.id') ->latest() ->take(10); })->latest(); }
之后直接使用Category::with('latestPosts')->get()即可。
内容的提问来源于stack exchange,提问作者Pooria Sadeghy
相关产品推荐
相关产品推荐

