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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 22:39:15