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

ApolloServer无法正确映射Neo4j关联节点问题求助

问题:GraphQL查询Neo4j时无法正确映射关联节点

我正在开发一个通过GraphQL查询Neo4j数据库的项目,目标是获取中心Company节点及其关联的Company或Person节点,但在JavaScript代码中无法正确映射这些关联节点。目前已成功获取中心Company节点,但connectedNodes的映射逻辑存在问题,console.log输出节点列表却未达到预期效果。我尝试过使用可选链(?.)、节点类型判断等方法,仍未解决问题,恳请提供正确的映射方案指导。

原代码片段

const { ApolloServer, gql } = require('apollo-server');
const neo4j = require('neo4j-driver');
const { GraphQLJSON } = require('graphql-scalars');

const typeDefs = gql`
  scalar JSON

  type Company {
    id: ID!
    orgNo: String!
    companyName: String!
    address: String!
    city: String!
    zipCode: String!
    connectedNodes: [Node]
  }
  
    type Person {
    id: ID!
    role: String
    ZipCode: String
    Street: String
    test_id: String
    label: String
    City: String
    RoleCode: String
    Name: String
  }


  type Node {
    id: ID!
    labels: [String]
    properties: JSON
  }

  type Query {
    company(orgNo: String!): Company
  }
`;


const driver = neo4j.driver(
  'bolt://localhost:7687',
  neo4j.auth.basic('neo4j', 'password')
);

const resolvers = {
  JSON: GraphQLJSON,

  Query: {
    company: async (_, { orgNo }) => {
      const session = driver.session();
      const result = await session.run(
        `MATCH (source:Company {OrgNo: $orgNo})
        OPTIONAL MATCH path = (source)-[*1..3]-(target)
        WHERE NONE(rel IN relationships(path) WHERE rel.RoleCode IN ['REV', 'SU'])
        RETURN source, COLLECT(DISTINCT target) AS connected_nodes`,
        { orgNo }
      );
      await session.close();
      
      const companyNode = result.records[0]?.get('source')?.properties;
      if (!companyNode) return null;
      
      const connectedNodes = result.records[0]?.get('connected_nodes')?.map(record => {
        const nodeType = record && record.labels?.[0];
        const nodeProperties = record && record.properties;
        


        if (record && record.labels.includes('Company')) {
          return {
            id: record.identity?.toString() || null,
            labels: record.labels || [],
            properties: nodeProperties || {}
          };
        } else if (record && record.labels.includes('Person')) {
          return {
            id: nodeProperties && nodeProperties['test_id']?.toString() || null,
            labels: record.labels || [],
            properties: nodeProperties || {}
          };
        }
        
        
        return node;
      }) || [];
      
      
      // console.log(connectedNodes)

      const company = {
        id: companyNode && companyNode['identity']?.toString() || '',
        orgNo: companyNode && companyNode['OrgNo'] || null,
        companyName: companyNode && companyNode['CompanyName'] || null,
        address: companyNode && companyNode['Address'] || null,
        city: companyNode && companyNode['City'] || null,
        zipCode: companyNode && companyNode['ZipCode'] || ''
      };
      

      return company;
    },
  },
};




const server = new ApolloServer({
  typeDefs,
  resolvers,
});

server.listen().then(({ url }) => {
  console.log(`Server running at ${url}`);
});

问题分析与修复方案

1. 未将关联节点加入返回对象

当前代码中已经正确生成了connectedNodes数组,但最终返回的company对象没有包含该字段,导致GraphQL接口无法返回关联节点数据。需要在company对象中添加connectedNodes属性。

2. 中心Company节点ID获取错误

companyNode是节点的properties对象,不存在identity属性。需要从原始的Neo4j节点对象(result.records[0].get('source'))中获取identity来生成ID。

3. 修复映射逻辑中的冗余与错误

  • 移除未定义的return node语句,避免返回无效值;
  • 简化节点属性的获取逻辑,利用可选链减少重复判断。

修复后的完整代码

const { ApolloServer, gql } = require('apollo-server');
const neo4j = require('neo4j-driver');
const { GraphQLJSON } = require('graphql-scalars');

const typeDefs = gql`
  scalar JSON

  type Company {
    id: ID!
    orgNo: String!
    companyName: String!
    address: String!
    city: String!
    zipCode: String!
    connectedNodes: [Node]
  }
  
  type Person {
    id: ID!
    role: String
    ZipCode: String
    Street: String
    test_id: String
    label: String
    City: String
    RoleCode: String
    Name: String
  }

  type Node {
    id: ID!
    labels: [String]
    properties: JSON
  }

  type Query {
    company(orgNo: String!): Company
  }
`;

const driver = neo4j.driver(
  'bolt://localhost:7687',
  neo4j.auth.basic('neo4j', 'password')
);

const resolvers = {
  JSON: GraphQLJSON,

  Query: {
    company: async (_, { orgNo }) => {
      const session = driver.session();
      const result = await session.run(
        `MATCH (source:Company {OrgNo: $orgNo})
        OPTIONAL MATCH path = (source)-[*1..3]-(target)
        WHERE NONE(rel IN relationships(path) WHERE rel.RoleCode IN ['REV', 'SU'])
        RETURN source, COLLECT(DISTINCT target) AS connected_nodes`,
        { orgNo }
      );
      await session.close();
      
      const sourceNode = result.records[0]?.get('source');
      if (!sourceNode) return null;
      const companyProperties = sourceNode.properties;
      
      const connectedNodes = result.records[0]?.get('connected_nodes')?.map(node => {
        const nodeProperties = node.properties;
        let nodeId = null;
        
        if (node.labels.includes('Company')) {
          nodeId = node.identity?.toString();
        } else if (node.labels.includes('Person')) {
          nodeId = nodeProperties?.test_id?.toString();
        }

        return {
          id: nodeId || null,
          labels: node.labels || [],
          properties: nodeProperties || {}
        };
      }) || [];
      
      const company = {
        id: sourceNode.identity.toString(),
        orgNo: companyProperties.OrgNo || null,
        companyName: companyProperties.CompanyName || null,
        address: companyProperties.Address || null,
        city: companyProperties.City || null,
        zipCode: companyProperties.ZipCode || '',
        connectedNodes // 关键:添加关联节点到返回对象
      };
      
      return company;
    },
  },
};

const server = new ApolloServer({
  typeDefs,
  resolvers,
});

server.listen().then(({ url }) => {
  console.log(`Server running at ${url}`);
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 10:25:02