Laravel 10.x 中推荐用 path 字段 + 前缀匹配实现无限级分类层级筛选:数据库加索引 path 字段,模型定义 withDescendants 和 childrenOf 作用域,新增/移动时自动维护 path。

在 Laravel 10.x 中实现无限级分类的层级筛选,核心是采用「嵌套集(Nested Set)」或「路径存储(Path-based)」模型,而非递归查询。前者性能高但增删复杂,后者更直观易维护,推荐用 path 字段 + 前缀匹配 方式实现高效层级筛选。
一、数据库设计:用 path 字段记录完整层级路径
在分类表(如 categories)中增加 path 字段(VARCHAR,建议长度 512),格式为 "0001/0002/0005" 或 "1/2/5"(推荐数字 ID 拼接,左补零可选,确保字典序正确)。同时保留 parent_id 便于维护和兼容性。
- 创建迁移示例:
在迁移中添加:
$table->unsignedBigInteger('parent_id')->nullable();$table->string('path')->index(); // 加索引提升查询效率
二、模型中定义层级关系与作用域(Scope)
在 Category 模型中定义父子关系,并添加关键作用域用于层级筛选:
- 定义父/子关系:
public function children() { return $this->hasMany(Category::class, 'parent_id'); }
- 添加作用域筛选某节点及其所有子级(含自身):
$path = self::findOrFail($id)->path;
return $query->where('path', 'like', $path . '/%')
->orWhere('id', $id);
}
- 筛选直接子级(一级子类):
return $query->where('parent_id', $parentId);
}
三、实际使用:按层级筛选分类数据
假设要获取「ID=3 的分类及其所有下级分类」用于后台筛选或前端树形展示:
- 控制器中调用:
- 若只需二级子类(即 ID=3 的直接子类):
- 配合搜索或其它条件(如只查启用状态):
->where('status', 1)
->orderBy('path')
->get();
四、自动维护 path 字段(关键!)
每次新增/移动分类时,必须更新 path。推荐在模型事件中处理:
- 新增时:读取父类
path,拼接自身 ID(如父 path 是"1/4",新分类 ID=12 →"1/4/12"); - 移动时:批量更新整棵子树的
path(可用事务 + 子查询或递归更新); - 简单起见,可在
Category::creating和Category::updating中统一处理,避免手动出错。
不复杂但容易忽略,path 一旦错位,层级筛选将完全失效。











