You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 20:05:24