数据库映射

这是 GraphQL Library 7 版本的文档。对于长期支持 (LTS) 版本 5,请参考 GraphQL Library 5 LTS 版本

本页面介绍了如何使用指令进行数据库映射。GraphQL 类型定义中的每种类型都可以映射到 Neo4j 数据库中的实体,例如节点、关系和关系属性。

@node

定义

"""Informs @neo4j/graphql of node metadata"""
directive @node(
  """The labels to map this GraphQL type to in the Neo4j database"""
  labels: [String!]
) on OBJECT

使用

@node 指令添加到 GraphQL 类型中,表示它对应于一个 Neo4j 节点。例如,要表示一个具有标签“Movie”和名为“title”的字符串类型属性的 Neo4j 节点:

type Movie @node {
    title: String
}

如果未特别指定,GraphQL 类型名称将用作所表示 Neo4j 节点的标签。可以通过使用 labels 参数来显式定义 Neo4j 节点标签。

labels 参数

您可以将可选参数 labels 附加到带有 @node 指令的 GraphQL 对象上。此参数列出了要在 Neo4j 中使用的标签,而不是使用 GraphQL 类型名称。

示例 1. 使用 labels 参数查询字段

考虑以下类型定义

type Dog @node(labels: ["K9"]) {
    name: String!
}

这是针对 Dog 节点的查询

{
  dogs {
    name
  }
}

生成的 Cypher 如下

MATCH (this: K9)
RETURN this { .name } as name

如果您想将 GraphQL 类型名称也用作标签,请同时指定两者。

示例 2. 使用带有两个条目的 labels 参数查询字段

考虑以下类型定义

type Dog @node(labels: ["Dog", "K9"]) {
    name: String!
}

以下是一个针对 Dog 节点的查询示例

{
  dogs {
    name
  }
}

生成的 Cypher 如下

MATCH (this:Dog:K9)
RETURN this { .name } as this

定义 labels 意味着您可以控制节点的数据库标签。Neo4j 中的索引和约束仅支持单个标签,其中使用 labels 参数的第一个元素。

使用 $jwt$context

在某些情况下,您可能希望根据请求用户生成动态标签。您可以使用变量 $jwt 在 JWT 中定义自定义标签。

示例 3. 在 labels 参数中使用 $jwt 变量查询字段

考虑以下类型定义

type User @node(labels: ["$jwt.username"]) {
    name: String!
}

以下查询根据用户 JWT 的不同产生不同的 Cypher 查询

{
  users {
    name
  }
}

假设 JWT 中存在一个值为 "username": "arthur" 的用户,Cypher 查询如下所示

MATCH (this:arthur)
RETURN this { .name } as this

同样,可以直接传递上下文值

type User @node(label: ["$context.appId"]) {
    name: String!
}

例如,如果您正在使用 Apollo 运行服务器

const server = new ApolloServer({
    schema: await neoSchema.getSchema(),
});

await startStandaloneServer(server, {
    context: async ({ req }) => ({ req, appId: "myApp" }),
});

@relationship

定义

"""
Instructs @neo4j/graphql to treat this field as a relationship. Opens up the ability to create and connect on this field.
"""
directive @relationship(
  type: String!
  """Valid and default directions for this relationship."""
  queryDirection: RelationshipQueryDirection = DEFAULT_DIRECTED
  direction: RelationshipDirection!
  """
  The name of the interface containing the properties for this relationship.
  """
  properties: String
  """
  Prevent all but these operations from being generated for this relationship
  """
  nestedOperations: [RelationshipNestedOperations!]! = [CREATE, UPDATE, DELETE, CONNECT, DISCONNECT, CONNECT_OR_CREATE]
  """Prevent aggregation for this relationship"""
  aggregate: Boolean = true
) on FIELD_DEFINITION

用法

关系通过用指令标记特定字段来表示——在这种情况下,即 @relationship。它定义了数据库中的关系类型以及该关系的走向。

要添加两个节点类型“Movie”和“Actor”并将两者连接起来

type Movie @node {
    title: String
    actors: [Actor!]! @relationship(type: "ACTED_IN", direction: IN)
}

type Actor @node {
    name: String
    movies: [Movie!]! @relationship(type: "ACTED_IN", direction: OUT)
}

@relationship 指令使用了两次,关系的两端各一次。这是使用 GraphQL 库对关系建模的标准方式。但是,这并不是类型定义本身的硬性要求,因为关系可以被特意指定得不够详尽,例如为了限制 API 层面的访问。

另请参阅:@relationship 字段配置

@relationshipProperties

定义

"""Required to differentiate between interfaces for relationship properties, and otherwise."""
directive @relationshipProperties on OBJECT

@relationshipProperties 只能在接口(interfaces)上使用。

用法

为了向关系添加属性,请在类型定义中添加一个新类型,并使用 @relationshipProperties 指令进行修饰。

例如,对于“ACTED_IN”关系,添加一个“roles”属性

type Movie @node {
    title: String
    actors: [Actor!]! @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn")
}

type Actor @node {
    name: String
    movies: [Movie!]! @relationship(type: "ACTED_IN", direction: OUT, properties: "ActedIn")
}

type ActedIn @relationshipProperties {
    roles: [String]
}

请注意,除了此类型外,现有的 @relationship 指令中还增加了一个 properties 键。更多信息,请参阅 关系

@alias

定义

"""
Instructs @neo4j/graphql to map a GraphQL field to a Neo4j node or relationship property.
"""
directive @alias(
  """The name of the Neo4j property"""
  property: String!
) on FIELD_DEFINITION

用法

此指令将 GraphQL 字段映射到节点或关系上的 Neo4j 属性。它可用于任何不是 @cypher@relationship 的字段。

例如:

type User @node {
    id: ID! @id @alias(property: "dbId")
    username: String!
}
type User @node {
    id: ID! @id
    username: String! @alias(property: "dbUserName")
    livesIn: [City!]! @relationship(direction: OUT, type: "LIVES_IN", properties: "UserLivesInProperties")
}

type City @node {
    name: String
}

type UserLivesInProperties @relationshipProperties {
    since: DateTime @alias(property: "moveInDate")
}
别名中的属性会自动转义(用反引号 `` 包裹),因此无需在其周围添加转义字符。