# treebark **Repository Path**: damengde/treebark ## Basic Information - **Project Name**: treebark - **Description**: No description available - **Primary Language**: Unknown - **License**: MulanPSL-2.0 - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-06-05 - **Last Updated**: 2024-06-05 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # treebark ## 契机 在我们实际开发中,经常会需要处理“树状结构”的数据,如部门结构,菜单结构,权限结构等。由于这种类型的数据,多用于展示,所以我们通常会使用在数据库中加入“parentId”,然后通过 递归来查询全量的数据。
但随着需求的迭代,很多“树状结构”的数据需要被使用到更多的查询中,比如:需要频繁的查询某个节点的所有子节点,查询某个节点的所有兄弟节点。 这种情况下,“parentId+迭代”就显得不那么友好了。
于是我们开发了treebark,它能用来帮助你,从“parentId+迭代”转变为MPTT!(我们还提供了数据清洗的方法) ## 预排序遍历树算法(MPTT)树 预排序遍历树算法全称是:Modified Preorder Tree Traversal 简称 MPTT。主要应用于层级关系的存储和遍历。 MPTT在遍历的时候很快,但是其他的操作就会变得很慢。对于需要频繁查询,但修改不是很频繁的树状数据结构, 使用MPTT树进行存储,可以让数据查询更为高效。 一棵标准的树结构: ![树的遍历](./doc/tree.png) ## 约定大于配置 ### 字段标签:`bark` 1. 属性:`name`: 字段绑定关系,可选,默认当前字段名首字母小写的形式 , 2. 属性:`column`: 数据库字段名,可选,默认当前字段名称小写下划线形式 3. 字段关系表: | name | column | name | type | |:----------:|:-----------:|:-----:|:-------------:| | `id` | `id` | 节点id | string or int | | `parentId` | `parent_id` | 父节点id | string or int | | `level` | `level` | 节点等级 | int | | `treeId` | `tree_id` | 树根id | string or int | | `lft` | `lft` | 节点左序号 | int | | `rgt` | `rgt` | 节点右序号 | int | > 注意:name属性是强绑定的,上述表格字段必须全部包含, column属性可任意 #### 示例 1. 满配 ```go type SysDepartModel struct { Id string `gorm:"primaryKey" bark:"name:id;colum:id" ` // 节点id ParentId string `gorm:"column:parent_id" bark:"name:parentId;colum:parent_id"` // 父节点id Level int64 `gorm:"column:level" bark:"name:level;colum:level" ` // 节点等级 TopParentId string `gorm:"column:top_parent_id" bark:"name:treeId;colum:top_parent_id"` // 顶级父节点id Lft int64 `gorm:"column:lft" bark:"name:lft;colum:lft"` // 左节点序号 Rgt int64 `gorm:"column:rgt" bark:"name:rgt;colum:rgt"` // 右节点序号 } ``` 2. 简配 ```go type SysDepartModel struct { Id string `gorm:"primaryKey" bark:"colum:id" ` // 节点id ParentId string `gorm:"column:parent_id" ` // 父节点id Level int64 `gorm:"column:level" ` // 节点等级 TopParentId string `gorm:"column:top_parent_id" bark:"treeId"` // 顶级父节点id Lft int64 `gorm:"column:lft"` // 左节点序号 Rgt int64 `gorm:"column:rgt"` // 右节点序号 } ``` > 拿TopParentId举例:treebark中的name:treeId是必须指定的,而TopParentId不管怎么转换与treebark都不相同,所以需要指定。 TopParentId驼峰转下划线之后等于top_parent_id,与数据库字段名一致,所以不需要指定column。 ## 使用方法 1. 项目引入treebark ```shell go get gitlab.zhijiasoft.com/golang/treebark.git ``` 2. 定义`model` 并绑定bark标签 ```go type SysDepartModel struct { Id string `gorm:"primaryKey" bark:"colum:id" ` // 节点id ParentId string `gorm:"column:parent_id" ` // 父节点id Level int64 `gorm:"column:level" ` // 节点等级 TopParentId string `gorm:"column:top_parent_id" bark:"treeId"` // 顶级父节点id Lft int64 `gorm:"column:lft"` // 左节点序号 Rgt int64 `gorm:"column:rgt"` // 右节点序号 } ```` 3. 创建树`treeService`。其中db类型为`*gorm.DB`。 ```go treeService, err := service.CreateTreeServiceFactory[SysDepartModel,mapper.GORM](db, &SysDepartModel{}) ``` ### 操作 #### 节点增加 使用`Create`方法可以快速创建节点。需要确保`node`的`ParentId`和`Level`信息正确。如果`Level`=1为空,则将插入一棵新的树的根节点。 ```go err := treeService.Create(node) ``` #### 节点删除 按ID删除方法`DeleteById` ```go err := manager.DeleteById(19) ``` #### 节点查询 ```go // 查询node节点的所有子孙节点,不包含本身 models, err = treeService.QueryDescendentByParentId(11) ``` #### Rebuild方法 使用场景: 1. 当有节点不是通过`TreeService`中的方法创建,需要修正树中节点的MPTT信息; 2. 当并发处理导致树上的MPTT信息错乱时; 3. 其他任何导致树上MPTT信息不准确,需要修正这些数据时 都可以调用`Rebuild`来修正整个森林,`PartialRebuild`修正特定的树: ```go err = treeService.Rebuild() err = treeService.PartialRebuild(treeID) ``` ## 后续计划 ~~1. 字段映射动态配置,支持在创建`Service`时指定字段映射关系~~ ~~2. 字段要求简化,除 `lft`, `rgt` 外,其他字段去除限制~~ 3. 查询和创建方法扩展,增加左节点,右节点等插入和查询方法