Laravel API中如何将数据格式化为树形结构返回
Laravel 实现层级数据树形结构API返回
以下两种方案都可以直接适配你parent_id关联父级ID、顶层节点parent_id=0的表结构,返回格式完全匹配你需要的带child嵌套的树形结构。
方案一:Eloquent 关联递归预加载(代码最简洁,适合中小数据量)
利用Laravel Eloquent的自关联+自动递归预加载能力,不用手动写递归逻辑,代码可维护性最高。
- 首先在对应模型(例如分类模型
Category)中定义自引用一对多关联:
// app/Models/Category.php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasMany; class Category extends Model { // 根据自身表字段调整允许批量赋值的字段列表 protected $fillable = ['parent_id', 'name_en', 'name_ja']; /** * 关联当前节点下的所有子节点 * 方法名设为child,和接口返回的字段名保持一致 */ public function child(): HasMany { return $this->hasMany(Category::class, 'parent_id', 'id') // 调用with递归预加载所有层级的子节点,无需手动逐层查询 ->with('child') // 如需子节点按指定字段排序,可加这行,按自己表的排序字段调整即可 // ->orderBy('sort', 'asc'); } }
- 在控制器中编写查询逻辑,直接查询顶层节点即可自动带出所有层级子节点:
// app/Http/Controllers/Api/CategoryController.php public function categoryTree() { $tree = Category::query() ->where('parent_id', 0) // 只查顶层节点 ->with('child') // 触发关联递归预加载 ->get() // 不需要返回的字段(比如创建、更新时间)可以在这里隐藏 ->makeHidden(['created_at', 'updated_at']); return response()->json($tree); }
方案二:一次性查全量数据手动组装(性能最优,适合千条以上大数据量)
如果你的层级数据量很大,用Eloquent关联预加载会产生较多SQL查询,可以先一次性取出所有扁平数据,通过引用递归组装树,全程仅执行1条SQL,性能更好。
public function categoryTree() { // 一次性取出所有需要的字段,仅执行1条SQL $allNodes = Category::query()->get(['id', 'parent_id', 'name_en', 'name_ja'])->toArray(); $tree = []; $nodeMap = []; // 先把所有节点以ID为键建立索引,初始化child空数组 foreach ($allNodes as $node) { $node['child'] = []; $nodeMap[$node['id']] = $node; } // 遍历节点挂载到对应父级下 foreach ($nodeMap as $id => &$node) { if ($node['parent_id'] === 0) { // 顶层节点直接放入树结构根数组 $tree[] = &$node; } else { // 非顶层节点挂载到对应父节点的child数组中 if (isset($nodeMap[$node['parent_id']])) { $nodeMap[$node['parent_id']]['child'][] = &$node; } } } return response()->json($tree); }
注意:如果存在脏数据(比如子节点的parent_id对应的父节点不存在),手动组装方案里会自动过滤这部分无效节点;如果需要保留可以自行调整判断逻辑。
内容的提问来源于stack exchange,提问作者Trần Quang Thìn
相关产品推荐
相关产品推荐

