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

Laravel中如何合并父分类与子分类的文章?

我来给你几个实用的方案,帮你搞定父分类及其所有子分类的文章合并问题~

方案一:递归获取所有分类ID,一次性查询文章(适合中小型数据量)

首先在Category模型里加一个辅助方法,递归获取当前分类及其所有子分类的ID集合:

public function getAllDescendantIds()
{
    // 先把当前分类ID加入数组
    $ids = [$this->id];
    
    // 递归遍历所有子分类,合并它们的ID
    foreach ($this->children as $child) {
        $ids = array_merge($ids, $child->getAllDescendantIds());
    }
    
    return $ids;
}

然后在控制器里,用这些ID一次性查询所有关联的文章,记得去重(避免同一篇文章属于多个分类时重复展示):

public function show_category($slug){
    $category = $this->category->findBySlug($slug);
    // 获取当前分类+所有子分类的ID集合
    $allCategoryIds = $category->getAllDescendantIds();
    
    // 通过Post模型的分类关联查询所有匹配的文章,去重
    $posts = Post::whereHas('categories', function ($query) use ($allCategoryIds) {
        $query->whereIn('category_id', $allCategoryIds);
    })->distinct()->get();

    return view('post.category.show',compact('posts','category'));
}

注意:要确保Post模型里有对应的分类关联:

public function categories()
{
    return $this->belongsToMany(Category::class, 'post__post_category_relations', 'post_id', 'category_id');
}

方案二:使用嵌套集合优化(适合分类层级深、数据量大的场景)

如果你的分类层级复杂、数据量较多,递归查询会有性能问题,推荐用laravel-nestedset包来快速获取所有后代分类:

  1. 先安装包:
composer require kalnoy/nestedset
  1. 在Category模型里引入嵌套集合特性:
use Kalnoy\Nestedset\NodeTrait;

class Category extends Model
{
    use NodeTrait;
    // ... 你的其他模型代码
}
  1. 控制器里直接获取所有相关分类ID并查询文章:
public function show_category($slug){
    $category = $this->category->findBySlug($slug);
    // 获取当前分类+所有子分类的ID(嵌套集合提供的快捷方法)
    $allCategoryIds = $category->descendantsAndSelf()->pluck('id');
    
    $posts = Post::whereHas('categories', function ($query) use ($allCategoryIds) {
        $query->whereIn('category_id', $allCategoryIds);
    })->distinct()->get();

    return view('post.category.show',compact('posts','category'));
}

这个方案的查询效率比递归高很多,因为嵌套集合用数据库的范围查询替代了递归遍历。

方案三:递归合并文章(适合小数据量场景)

如果你的分类数据很少,也可以直接在模型里递归合并所有关联文章:

public function allPosts()
{
    // 先获取当前分类的文章
    $posts = $this->posts;
    
    // 递归合并所有子分类的文章
    foreach ($this->children as $child) {
        $posts = $posts->merge($child->allPosts());
    }
    
    // 去重后返回
    return $posts->unique('id');
}

控制器里直接调用:

public function show_category($slug){
    $category = $this->category->findBySlug($slug);
    $posts = $category->allPosts();

    return view('post.category.show',compact('posts','category'));
}

注意:这个方案会产生多次数据库查询(每个子分类一次),数据量大时不推荐使用。

关键注意点

  • 文章去重:一定要用distinct()(数据库层去重)或unique('id')(集合层去重),避免同一篇文章因属于多个分类而重复展示。
  • 预加载优化:如果用方案一,记得预加载子分类避免N+1查询:$category = $this->category->with('children')->findBySlug($slug);

内容的提问来源于stack exchange,提问作者justcntt

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 07:47:02