如何用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;
关键说明
- 递归逻辑:
buildTree遍历器会为每个节点生成title和children字段,其中children通过递归调用自身处理所有uses_process出边的子节点,直到无后续节点为止。 - 空节点处理:通过
choose()判断子节点数组是否为空,可灵活返回空数组、null或移除children字段(需调整对应逻辑)。 - 兼容性:该写法不依赖Lambda表达式,完全兼容AWS Neptune的Gremlin规范。
若需让叶子节点不显示children字段,可修改choose部分逻辑:
.by( __.out('uses_process') .map(buildTree) .fold() .choose( __.unfold(), __.project('children').by(__.identity()), __.constant({}) ) .unfold() )
内容的提问来源于stack exchange,提问作者Snappyjs
相关产品推荐
相关产品推荐

