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

如何用Gremlin递归生成JSON树形结构(替代tree(),适配Tinkerpop 3.5)

递归生成Gremlin树形JSON结构(避开.tree()方法)

问题背景

使用Tinkerpop 3.5数据库(本地容器部署,线上采用AWS Neptune),需要基于现有Process节点数据生成JSON树形结构。尝试过在repeat步骤后调用.tree(),但Node.js Gremlin客户端返回的结果包含@type/@values键,且所有内容以数组形式嵌套,解析难度极大。目前已实现固定3层深度的投影代码,希望能递归执行__.out('uses_process')直到无后续节点,生成完整树形结构,且不使用.tree()。

现有固定层级代码

const v = await this.g.V(partnerId)
    .out('uses_process').project('title', 'children').by('title')
    .by(
        __.out('uses_process').project('title', 'children').by('title').by(
            __.out('uses_process').project('title', 'children').by('title').by(
                __.out('uses_process').project('title').by('title'),
            ).fold(),
        ).fold(),
    )
    .next();

期望JSON输出格式

{
  "title": "1st Level",
  "children": [
    {
      "title": "2nd level",
      "children": [
        {
          "title": "3rd level",
          "children": [
            {
              "title": "4th level"
            }
          ]
        }
      ]
    }
  ]
}

注:原示例中第4层节点的children为单个对象,调整为数组更符合树形结构一致性,若需保持原格式可修改逻辑

示例测试数据

g.addV('Process').property('title', '1st level').as('root').
addV('Process').property('title', '2nd level').as('2nd').addE('uses_process').from('root').to('2nd').
addV('Process').property('title', '3rd level').as('3rd').addE('uses_process').from('2nd').to('3rd').
addV('Process').property('title', '4th level').as('4th').addE('uses_process').from('3rd').to('4th')

解决方案:递归投影实现动态树形

利用Gremlin的递归投影能力,结合fold()和choose()判断子节点存在性,动态生成完整树形结构:

// 定义递归遍历器,生成单节点的树形结构
const buildTree = __.project('title', 'children')
  .by('title')
  .by(
    __.out('uses_process')
      .map(buildTree) // 递归调用自身处理子节点
      .fold() // 将子节点集合转为数组
      .choose(
        __.unfold(), // 判断是否存在子节点
        __.identity(), // 有子节点则保留数组
        __.constant([]) // 无子节点则返回空数组(可按需改为null/空对象)
      )
  );

// 执行查询,从指定根节点开始生成完整树形
const result = await this.g.V(partnerId)
  .map(buildTree)
  .next();

// 提取最终树形数据(规避客户端返回的@type/@values包装)
const treeData = result.value;

关键说明

  1. 递归逻辑:buildTree遍历器会为每个节点生成title和children字段,其中children通过递归调用自身处理所有uses_process出边的子节点,直到无后续节点为止。
  2. 空节点处理:通过choose()判断子节点数组是否为空,可灵活返回空数组、null或移除children字段(需调整对应逻辑)。
  3. 兼容性:该写法不依赖Lambda表达式,完全兼容AWS Neptune的Gremlin规范。

若需让叶子节点不显示children字段,可修改choose部分逻辑:

.by(
  __.out('uses_process')
    .map(buildTree)
    .fold()
    .choose(
      __.unfold(),
      __.project('children').by(__.identity()),
      __.constant({})
    )
    .unfold()
)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 08:35:26