如何在Go语言中构造指定嵌套树形结构并从数据库表加载对应数据
Go构造嵌套树形结构的实现方案
不要使用多层嵌套map实现递归树形结构,这种方式灵活性差、维护难度高,推荐使用递归结构体实现,具体方案如下:
1. 定义递归节点结构体
首先定义递归结构对应树形节点,和目标JSON结构字段一一对应:
type TreeNode struct { UUID string `json:"uuid"` Label string `json:"label"` Children []*TreeNode `json:"children,omitempty"` // 无孩子节点时序列化自动忽略该字段 }
2. 核心实现逻辑
你的数据库行存储的是叶子节点到根节点的路径:level4对应根节点label、level3对应二级节点label、level2对应三级节点label、level1对应叶子节点label,仅叶子节点的uuid直接从数据库取,上层节点的uuid可根据业务规则生成。
我们通过缓存已创建的节点避免重复构建,逐层挂载节点到对应父节点的children数组中即可。
3. 完整可运行代码示例
package main import ( "encoding/json" "fmt" ) // DbRow 对应数据库查询返回的每行数据结构 type DbRow struct { Uuid string Level1 string // 叶子节点label Level2 string // 三级节点label Level3 string // 二级节点label Level4 string // 根节点label } // TreeNode 树形节点结构 type TreeNode struct { UUID string `json:"uuid"` Label string `json:"label"` Children []*TreeNode `json:"children,omitempty"` } func main() { // 模拟从数据库读取的示例数据 rows := []DbRow{ {Uuid: "uuid5", Level1: "label5", Level2: "label3", Level3: "label2", Level4: "label1"}, {Uuid: "uuid7", Level1: "label7", Level2: "label3", Level3: "label2", Level4: "label1"}, {Uuid: "uuid6", Level1: "label6", Level2: "label4", Level3: "label2", Level4: "label1"}, } // 缓存已创建的节点,key为 层级+label 避免不同层级同label重复,value为节点指针 nodeCache := make(map[string]*TreeNode) var root *TreeNode for _, row := range rows { // 按根到叶子的路径顺序处理 path := []string{row.Level4, row.Level3, row.Level2, row.Level1} var currentParent *TreeNode for level, label := range path { // 构造缓存key,层级+label唯一标识节点 cacheKey := fmt.Sprintf("%d_%s", level, label) // 节点已存在直接跳过创建 if node, ok := nodeCache[cacheKey]; ok { currentParent = node continue } // 创建新节点 newNode := &TreeNode{Label: label} // 叶子节点用数据库返回的uuid,上层节点按业务规则生成uuid if level == len(path)-1 { newNode.UUID = row.Uuid } else { // 可替换为你实际的上层节点uuid生成逻辑,这里为匹配示例用固定规则生成 newNode.UUID = fmt.Sprintf("uuid%d", level+1) } nodeCache[cacheKey] = newNode // 挂载节点到父节点 if currentParent == nil { root = newNode } else { currentParent.Children = append(currentParent.Children, newNode) } currentParent = newNode } } // 序列化输出验证结果 jsonRes, err := json.MarshalIndent(root, "", " ") if err != nil { panic(err) } fmt.Println(string(jsonRes)) }
代码运行后输出的JSON结构完全匹配你给出的目标格式,如果你需要调整上层节点的uuid生成规则,直接修改对应代码块即可。如果存在同层级label重复的场景,也可以调整缓存key的生成规则适配你的业务。
内容的提问来源于stack exchange,提问作者cnknob
相关产品推荐
相关产品推荐

