推荐Nodejs下高效存储树到数据库工具库-FlexTree

官网 | English

FlexTreeNodejs下一个基于左右值算法的树结构库,它提供了一种简单的方式来存储和操作树形结构数据。
FlexTree提供了简单而丰富的API让你可以轻松的操作树,如增删改查、遍历、移动、查询等。

主要特性:

  • 基于左右值算法,高效的树结构存储和访问
  • 简单易用的API
  • 丰富的树操作,如增删改查、遍历、移动、查询等
  • 采用TypeScript开发,提供完整友好的类型定义
  • 支持任意数据库存储,如SQLiteMySQLPostgreSQL
  • 95%+的测试覆盖率,保证代码质量
  • 适用Node.js环境

访问官网

了解树模型

在开发Nodejs应用时,当需要在数据库中存储树时,常见的存储结构有以下几种:

  • 邻接列表结构
  • 路径枚举结构
  • 嵌套树结构
  • 闭包表结构

以上算法各有优缺点,应该根据实际的应用场景选择合适的算法。

嵌套树模型(Nested Set Model)也被称为左右值模型,它是一种用于存储树形结构数据的方法,通过两个字段(通常被称为 lftrgt)来表示节点在树中的位置。

在嵌套树模型中,每个节点的lft值都小于其所有子节点的lft值,rgt值都大于其所有子节点的 rgt 值。这样,我们可以通过一个简单的查询来获取一个节点的所有后代,只需要查找lftrgt 值在这个范围内的所有节点即可。

嵌套树模型的左右值分布方式是通过深度优先遍历(Depth-First Search)来确定的。在遍历过程中,每当进入一个节点时,就分配一个 lft 值,每当离开一个节点时,就分配一个 rgt 值。这样,每个节点的 lftrgt 值就形成了一个区间,这个区间内的所有值都对应该节点的子节点。

例如,下面是一个嵌套树模型的例子:

id leftValue rightValue name
1 1 14 root
2 2 9 A
3 10 11 B
4 12 13 C
5 3 4 A-1
6 5 6 A-2
7 7 8 A-3
  • root
    • A
      • A-1
      • A-2
      • A-3
    • B
    • C

快速开始

第1步:安装核心库

首先安装flextree核心库。

ts 复制代码
npm install flextree
// or
yarn add flextree
// or
pnpm add flextree

第2步:配置数据库适配器

接下来,取决于您的应用是如何访问数据库,你需要安装相应的数据库适配器。

本例中,我们使用Sqlite,安装数据库安装flextree-sqlite-adapter

ts 复制代码
npm install flextree-sqlite-adapter
// or
yarn add flextree-sqlite-adapter
// or
pnpm add flextree-sqlite-adapter

flextree-sqlite-adapterflextreesqlite3数据库驱动,基于sqlite3数据库存储。

如果你使用的是MySQLPostgreSQL等数据库,可以安装对应的驱动,如flextree-prima-adapter,或者基于flextree提供的IFlexTreeAdapter自定义驱动。

第3步:创建树表

接下来,我们需要在数据库中创建组织架构树表org

如果你使用的是sqlite数据库,可以使用以下sql语句创建表:

ts 复制代码
import SqliteAdapter from 'flextree-sqlite-adapter';

const sqliteAdapter = new SqliteAdapter("org.db")
await sqliteAdapter.open()
await sqliteAdapter.exec(`
    CREATE TABLE IF NOT EXISTS  org (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        name VARCHAR(60),  
        level INTEGER,  
        leftValue INTEGER, 
        rightValue INTEGER,
`)

以上,我们他创建了一个org表,包含以下字段:

字段名 类型 说明
id INTEGER 主键,自增
name VARCHAR(60) 名称
level INTEGER 层级
leftValue INTEGER 左值
rightValue INTEGER 右值

一般情况下,以上字段是必须的,你可以根据实际情况添加其他字段。

提示 :一般情况下,创建表是由应用程序自行完成的,flextree不负责创建表。本节仅演示需要创建的树表结构。

第4步:创建树管理器

接下来,我们创建一个组织架构树管理器OrgManager,用于管理组织架构树。

ts 复制代码
import { FlexTreeManager } from 'flextree';
import SqliteAdapter from 'flextree-sqlite-adapter';

const sqliteAdapter = new SqliteAdapter("org.db")
await sqliteAdapter.open()

const orgManager = new FlexTreeManager("org",{
    adapter: sqliteAdapter     
})

第5步:添加树节点

然后我们就可以开始向组织架构树中添加节点了。

ts 复制代码
// 创建一个根节点
await orgManager.createRoot({
    name: "A公司"
})
// 添加组织架构的一级部门子节点
await orgManager.addNodes([
    { name: "行政中心" },
    { name: "市场中心" },
    { name: "研发中心"} 
])
 
// 添加行政中心的部门子节点.
const node = await orgManager.findNode({name:"行政中心"})
await orgManager.addNodes( [
        { name: "总裁办" },
        { name: "人力资源部" },
        { name: "财务部" },
        { name: "行政部" },
        { name: "法务部" },
        { name: "审计部" }
    ],node)   // 添加为node的子节点

我们可以使用addNodes方法向树中添加节点,addNodes方法支持批量添加节点,支持多种形式的添加子节点。

第6步:访问树

以上我们已经创建了一棵完整的树,接下来我们可以通过两种形式来访问树。

  • 通过FlexTreeManager访问树
  • 通过FlexTree对象访问树

获取节点

ts 复制代码
// 获取所有节点
await orgManager.getNodes() 
// 限定层级获取节点,仅获取第1-3层节点,不包含第4层及以下节点
await orgManager.getNodes(3) 
// 根据id获取节点
await orgManager.getNode(1) 
// 获取树根节点
await orgManager.getRoot()

// 获取name=行政中心的节点
const node = await orgManager.findNode({name:"行政中心"})
// 获取节点<行政中心>的子节点集
await orgManager.getChildren(node)
// 获取节点<行政中心>的所有后代节点集
await orgManager.getDescendants(node)
// 获取节点<行政中心>的所有后代节点集,包括自身
await orgManager.getDescendants(node,{includeSelf:true})
// 获取节点<行政中心>的所有后代节点集,包括限定层级
await orgManager.getDescendants(node,{level:2})
// 获取节点<行政中心>的子节点集,level=1相当于只获取直接子节点
await orgManager.getDescendants(node,{level:1})

// 获取节点<行政中心>的所有祖先节点集
await orgManager.getAncestors(node) 
// 获取节点<行政中心>的父节点
await orgManager.getParent(node) 
// 获取节点<行政中心>的所有兄弟节点集
await orgManager.getSiblings(node)  
// 获取节点<行政中心>的所有兄弟节点集,包括自身
await orgManager.getSiblings(node,{includeSelf:true})  
// 获取节点<行政中心>的前一个兄弟节点
await orgManager.getNextSibling(node)
// 获取节点<行政中心>的后一个兄弟节点
await orgManager.getPrevSibling(node)

查找节点

ts 复制代码
// 查找name=行政中心的节点,只返回第一个满足条件的节点
await orgManager.findNode({name:"行政中心"})
// 查找所有level=1的节点集
await orgManager.findNodes({level:1})

:::warning 提示
FlexTree只提借供简单的查询功能,如果需要更复杂的查询,可以使用数据库的查询功能。

:::

移动节点

ts 复制代码
import { FirstChild, LastChild,PreviousSibling,NextSibling } from 'flextree'
const admin = await orgManager.findNode({name:"行政中心"})
const market = await orgManager.findNode({name:"市场中心"})

// 将行政中心移动到市场中心下,成为其最后一个子节点
await orgManager.move(admin,market)  
await orgManager.move(admin,market,LastChild)  // 与上面等价
// 将行政中心移动到市场中心下,成为其第一个子节点
await orgManager.move(admin,market,FirstChild)
// 将行政中心移动到市场中心前,成为其前一个兄弟节点
await orgManager.move(admin,market,PreviousSibling)
// 将行政中心移动到市场中心后,成为其后一个兄弟节点
await orgManager.move(admin,market,NextSibling)

// 将行政中心上移
await orgManager.moveUpNode(admin)  
// 将行政中心下移
await orgManager.moveDownNode(admin)  

删除节点

ts 复制代码
const admin = await orgManager.findNode({name:"行政中心"})
// 删除行政中心节点以及其所有后代节点
await orgManager.deleteNode(admin)
// 清空树
await orgManager.clear()  

查询节点关系

ts 复制代码
const admin = await orgManager.findNode({name:"行政中心"})
const market = await orgManager.findNode({name:"市场中心"})

// 返回admin节点与market节点的关系
const relation = await getNodeRelation(admin,market)

// relation取值范围
export enum FlexTreeNodeRelation {
    Self = 0,
    Parent = 1,
    Child = 2,
    Siblings = 3,
    Descendants = 4,
    Ancestors = 5,
    DiffTree = 6,
    SameTree = 7,
    SameLevel = 8,
    Unknow = 9,
} 
 

访问官网

推荐

相关推荐
咖啡の猫1 小时前
数据库的基本概念
数据库
练习两年半的工程师1 小时前
使用React和google gemini api 打造一个google gemini应用
javascript·人工智能·react.js
小卓笔记2 小时前
keepalived应用
linux·服务器·数据库
勘察加熊人2 小时前
angular九宫格ui
javascript·ui·angular.js
八股文领域大手子3 小时前
Leetcode32 最长有效括号深度解析
java·数据库·redis·sql·mysql
鹏神丶明月天4 小时前
mybatis_plus的乐观锁
java·开发语言·数据库
左钦杨4 小时前
Nuxt2 vue 给特定的页面 body 设置 background 不影响其他页面
前端·javascript·vue.js
SelectDB技术团队4 小时前
天翼云:Apache Doris + Iceberg 超大规模湖仓一体实践
大数据·数据库·iceberg·doris·数据湖·湖仓一体·天翼云
烛阴5 小时前
JavaScript 调度:setTimeout 和 setInterval
前端·javascript
難釋懷5 小时前
JavaScript基础-获取元素
开发语言·javascript