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

如何用GraphQL与NestJS将部门数据解析为动态树形结构?

NestJS实现扁平化部门JSON转多级GraphQL树形结构

需求说明

给定扁平化的部门JSON数据:

{
    "departments": [
        {
            "id": 1,
            "name": "department 1",
            "parent_id": ""
        },
        {
            "id": 2,
            "name": "department 2",
            "parent_id": "1" 
        },
        {
            "id": 3,
            "name": "department 3",
            "parent_id": "1" 
        },
        {
            "id": 4,
            "name": "department 4",
            "parent_id": "2" 
        }
    ]
}

需要转换为带多级子节点的GraphQL树形结构:

{
    "id": 1,
    "name": "department 1",
    "children": [
        {
            "id": 2,
            "name": "department 2",
            "children": [
                {
                    "id": 4,
                    "name": "department 4"
                }
            ]
        },
        {
            "id": 3,
            "name": "department 3"
        }
    ]
}

且部门规模庞大,需支持动态多级子节点结构。


解决方案

1. 定义GraphQL ObjectType

使用@ObjectType装饰器递归定义部门类型,通过延迟函数() => [DepartmentType]避免循环引用问题:

import { ObjectType, Field, Int } from '@nestjs/graphql';

@ObjectType()
export class DepartmentType {
  @Field(() => Int)
  id: number;

  @Field()
  name: string;

  @Field(() => [DepartmentType], { nullable: true })
  children?: DepartmentType[];
}

2. 实现扁平化转树形结构的工具函数

通过Map存储部门实现O(1)查找,仅遍历两次数据完成树形构建,适合大规模数据处理:

import { DepartmentType } from './department.type';

// 定义原始部门数据类型
type RawDepartment = {
  id: number;
  name: string;
  parent_id: string;
};

export function convertToTree(rawDepartments: RawDepartment[]): DepartmentType[] {
  const departmentMap = new Map<number, DepartmentType>();
  const rootDepartments: DepartmentType[] = [];

  // 初始化所有部门节点并存入Map
  rawDepartments.forEach(dept => {
    departmentMap.set(dept.id, {
      id: dept.id,
      name: dept.name,
      children: [],
    });
  });

  // 挂载子节点到对应父节点
  rawDepartments.forEach(dept => {
    const parentId = dept.parent_id ? parseInt(dept.parent_id, 10) : null;
    if (parentId === null) {
      rootDepartments.push(departmentMap.get(dept.id)!);
    } else {
      const parentDept = departmentMap.get(parentId);
      parentDept?.children?.push(departmentMap.get(dept.id)!);
    }
  });

  return rootDepartments;
}

3. 在GraphQL Resolver中使用

在Resolver中调用转换函数,返回树形结构数据:

import { Query, Resolver } from '@nestjs/graphql';
import { DepartmentType } from './department.type';
import { convertToTree } from './department.util';
import { DepartmentService } from './department.service';

@Resolver(() => DepartmentType)
export class DepartmentResolver {
  constructor(private readonly departmentService: DepartmentService) {}

  @Query(() => [DepartmentType])
  async departmentsTree() {
    // 获取原始扁平化部门数据
    const rawDepartments = await this.departmentService.getRawDepartments();
    return convertToTree(rawDepartments);
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 01:25:18