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

如何将Neo4j查询结果转为D3可用的Graph JSON格式(Node.js)

将Neo4j查询结果转换为D3可视化所需的Graph JSON格式

问题分析

你当前直接返回Neo4j driver的原生查询结果,这种结构包含大量元数据,无法直接用于D3的力导向图可视化。需要将其转换为标准的{ nodes: [], links: [] }格式,其中:

  • nodes数组:每个元素包含节点的唯一ID、显示名称、分组等属性
  • links数组:每个元素包含边的起始节点ID、目标节点ID、关系类型等属性

解决方案

修改你的Express控制器代码,添加结果转换逻辑,具体实现如下:

import neo4j from 'neo4j-driver';
import {
  NEO4J_PASSWORD,
  NEO4J_URL,
  NEO4J_USERNAME,
} from '../../constants/index.js';

// 转换Neo4j结果为D3可用的Graph JSON格式
const transformToD3Graph = (neo4jResult) => {
  const nodes = [];
  const links = [];
  const nodeMap = new Map(); // 用Map避免重复添加节点

  // 遍历所有查询结果记录
  neo4jResult.records.forEach(record => {
    // 提取记录中的所有节点和关系
    record._fields.forEach(field => {
      // 处理节点
      if (field instanceof neo4j.types.Node) {
        const nodeId = field.elementId; // 使用Neo4j的唯一节点ID
        if (!nodeMap.has(nodeId)) {
          // 构建节点对象,可根据需求调整属性字段
          const node = {
            id: nodeId,
            name: field.properties.name || field.properties.title || nodeId, // 优先取业务名称,无则用节点ID
            group: field.labels[0] || 'Unknown', // 用节点标签作为分组标识
            ...field.properties // 保留节点所有原生属性
          };
          nodes.push(node);
          nodeMap.set(nodeId, node);
        }
      }
      // 处理关系
      else if (field instanceof neo4j.types.Relationship) {
        const link = {
          source: field.startNodeElementId,
          target: field.endNodeElementId,
          value: field.type, // 用关系类型作为边的标识
          ...field.properties // 保留关系所有原生属性
        };
        links.push(link);
      }
    });
  });

  return { nodes, links };
};

export const runMatchQuery = async (req, res) => {
  const query = req?.body?.query;
  if (query?.toLowerCase()?.includes('match')) {
    const driver = neo4j.driver(
      NEO4J_URL,
      neo4j.auth.basic(NEO4J_USERNAME, NEO4J_PASSWORD)
    );
    const session = driver.session();

    try {
      const result = await session.run(query);
      // 转换结果后返回
      const d3GraphData = transformToD3Graph(result);
      return res.status(200).json(d3GraphData);
    } catch (error) {
      console.log(error);
      return res.status(500).json({ message: error.message });
    } finally {
      await session.close();
      await driver.close();
    }
  } else {
    return res.status(405).json({ message: 'Query not permitted.' });
  }
};

关键说明

  1. 节点去重:使用Map存储已添加的节点ID,避免同一节点被重复加入nodes数组
  2. 属性适配:可根据你的业务节点属性调整name字段的取值逻辑(比如你的节点可能用username而非name)
  3. 兼容性:自动识别结果中的Node和Relationship类型,兼容仅返回节点、仅返回关系或两者混合的查询
  4. 属性保留:完整保留节点和关系的原生属性,方便D3可视化时扩展更多维度的展示

内容的提问来源于stack exchange,提问作者Hafiz Muhammad Bilal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 18:13:18