如何正确自省包含点分隔属性名的Neo4j Schema?
处理Neo4j自省含点分隔属性名的GraphQL Schema报错
问题重现
自省代码
import { toGraphQLTypeDefs } from "@neo4j/introspector"; import fs from "fs"; import neo4j from "neo4j-driver"; const driver = neo4j.driver( "neo4j://localhost:7687", neo4j.auth.basic("neo4j", "neo4j") ); const sessionFactory = () => driver.session({ defaultAccessMode: neo4j.session.READ }) async function main() { const typeDefs = await toGraphQLTypeDefs(sessionFactory) fs.writeFileSync('schema.graphql', typeDefs) await driver.close(); } main()
生成的有问题的GraphQL类型定义
type BaseEntity10 @node(labels: ["BaseEntity", "CompanyType", "CompositeEntity", "Requirable"]) { baseEntity16SCompanyTypeOf: [BaseEntity16!]! @relationship(type: "COMPANY_TYPE_OF", direction: IN) createdAt: BigInt! createdByBaseEntity4S: [BaseEntity4!]! @relationship(type: "CREATED_BY", direction: OUT) id: BigInt! lowerName: String! name: String! nameSlug: String! properties.lowerNameMonolithic: String! properties.lowerNameWhitespace: String! status: String! system: Boolean! updatedAt: BigInt! uuid: String! }
报错信息
Syntax Error: Unexpected character: ".".Locations: [{"line":24,"column":12}]
原因分析
GraphQL的字段命名规则不允许使用点(.)作为字段名的一部分,但Neo4j允许属性名包含点,直接通过自省生成的Schema违反了GraphQL语法规范,因此触发报错。
解决方案
方式1:替换点为下划线(简单直接)
修改自省代码,在写入文件前对生成的typeDefs字符串做替换,把字段名里的点换成下划线:
async function main() { let typeDefs = await toGraphQLTypeDefs(sessionFactory) // 将点分隔的字段名中的点替换为下划线 typeDefs = typeDefs.replace(/(\w+)\.(\w+):/g, '$1_$2:') fs.writeFileSync('schema.graphql', typeDefs) await driver.close(); }
处理后对应的字段会变为properties_lowerNameMonolithic: String!和properties_lowerNameWhitespace: String!,符合GraphQL命名规范。
方式2:嵌套为对象类型(贴合层级结构)
如果希望保留数据的层级结构,可以把properties定义为嵌套对象类型:
- 先定义
Properties类型:
type Properties { lowerNameMonolithic: String! lowerNameWhitespace: String! }
- 修改
BaseEntity10中的字段:
type BaseEntity10 @node(labels: ["BaseEntity", "CompanyType", "CompositeEntity", "Requirable"]) { baseEntity16SCompanyTypeOf: [BaseEntity16!]! @relationship(type: "COMPANY_TYPE_OF", direction: IN) createdAt: BigInt! createdByBaseEntity4S: [BaseEntity4!]! @relationship(type: "CREATED_BY", direction: OUT) id: BigInt! lowerName: String! name: String! nameSlug: String! properties: Properties! status: String! system: Boolean! updatedAt: BigInt! uuid: String! }
如果要自动化处理这种结构,需要解析GraphQL类型定义字符串并重构字段,实现起来相对复杂,适合对数据结构有明确层级要求的场景。
注意事项
- 使用方式1时,后续查询或操作这些字段需要注意:Neo4j中的原始属性名带点,要在Resolver中做映射,或者通过Neo4j GraphQL的自定义配置完成字段与属性的关联。
- 使用方式2时,要确保Neo4j中的属性存储结构能和GraphQL的嵌套类型匹配,或在Resolver中处理数据的转换逻辑。
内容的提问来源于stack exchange,提问作者alexanoid
相关产品推荐
相关产品推荐

