迁移到 7.0.0

这是 GraphQL Library 版本 7 的文档。有关长期支持 (LTS) 版本 5,请参阅GraphQL Library 版本 5 LTS

此页面列出了 Neo4j GraphQL Library 从 6.x 版本到 7.x 版本的所有重大变更以及如何更新。

如何更新

要更新您的 Neo4j GraphQL Library,请使用 npm 或您选择的包管理器

npm update @neo4j/graphql

重大变更

以下是 6.0.0 版到 7.0.0 版的所有重大变更列表。

移除 @unique 指令

不再支持 @unique 指令。它无法始终可靠地强制执行,可能导致与模式不匹配的数据不一致。

移除隐式过滤字段

隐式相等过滤字段已移除。请改用专用的 eq 字段

之前 之后
{
  movies(where: { title: "The Matrix" }) {
    title
  }
}
{
  movies(where: { title: { eq: "The Matrix" } }) {
    title
  }
}

excludeDeprecatedFieldsimplicitEqualFilters 选项已移除。

必需的 @node 指令

现在 @node 指令是必需的。没有 @node 指令的 GraphQL 对象类型不再被视为 Neo4j 节点表示。查询和变异只为带有 @node 指令的类型生成。

之前 之后
type Movie {
  title: String!
}
type Movie @node {
  title: String!
}

移除已弃用的 options 参数

已移除已弃用的 options 参数。

考虑以下类型定义

type Movie @node {
  title: String!
}

以下显示了选项的区别

之前 之后
{
  movies(options: { first: 10, offset: 10, sort: [{ title: ASC }] }) {
    title
  }
}
{
  movies(first: 10, offset: 10, sort: [{ title: ASC }]) {
    title
  }
}

excludeDeprecatedFieldsdeprecatedOptionsArgument 选项已移除。

移除已弃用的 directed 参数

已从查询中移除已弃用的 directed 参数。此参数以前允许您在查询时指定关系是有向的还是无向的。请改用 @relationship 指令的 queryDirection 参数。

excludeDeprecatedFieldsdirectedArgument 选项已移除。

变更 @relationshipqueryDirection 参数接受的值

在移除 directed 参数后,@relationship 指令的 queryDirection 参数现在只接受两个可能的值

  • DIRECTED (默认)

  • UNDIRECTED

不再支持以下值

  • DEFAULT_DIRECTED

  • DEFAULT_UNDIRECTED

  • DIRECTED_ONLY

  • UNDIRECTED_ONLY

移除已弃用的 typename_IN 过滤器

已移除已弃用的 typename_IN 过滤器。请改用 typename

之前 之后
{
  productions(where: { typename_IN: ["Movie", "Series"] }) {
    title
  }
}
{
  productions(where: { typename: ["Movie", "Series"] }) {
    title
  }
}

excludeDeprecatedFieldstypename_IN 选项已移除。

不再为 ID 字段生成聚合

ID 字段已从聚合选择集和聚合过滤器中排除。

移除单元素关系

已移除单元素关系,改用列表关系

之前 之后
type Movie @node {
    director: Person @relationship(type: "DIRECTED", direction: "IN")
}
type Movie @node {
    director: [Person!]! @relationship(type: "DIRECTED", direction: "IN")
}

单元素关系无法可靠地强制执行,可能导致数据与模式不一致。如果 GraphQL 模型需要一对一关系(例如在联邦中),现在可以使用 @cypher 指令来创建。

type Movie @node {
    director: Person
        @cypher(
            statement: """
            MATCH (this)-[:ACTED_IN]->(p:Person)
            RETURN p
            """
            columnName: "p"
        )
}

移除 connect overwrite 参数

已在连接操作中移除 overwrite 参数。

在 7.0.0 版中,连接操作已简化为始终在节点之间创建新关系,无论关系是否已存在。请参阅连接操作现在支持相同节点之间的多个关系

如果您必须更新现有关系而不是创建新关系,请使用 update 操作

mutation {
  updateMovies(
    update: {
      actors: [
        {
          where: { node: { name: { eq: "Keanu" } } }
          update: { edge: { role: { set: "Neo" } } }
        }
      ]
    }
  ) {
    movies {
      title
    }
  }
}

移除对 connectOrCreate 操作的支持

由于与其他操作相比,connectOrCreate 操作的功能集有限,因此已将其移除。

移除连接字段外部的聚合字段

已从模式中移除已弃用的聚合字段。请改用连接选择集内的聚合字段。

之前 之后
query {
    usersAggregate {
        count
    }
}
query {
    usersConnection {
        aggregate {
            count {
                nodes
            }
        }
    }
}

已从 excludeDeprecatedFields 设置中移除 deprecatedAggregateOperations 选项。

订阅现在是选择加入的

不再为所有 @node 类型自动生成订阅。在 7.x 版本中,需要 @subscription 指令才能启用此功能。您现在必须通过以下两种方式之一明确启用订阅,使用 @subscription 指令

  • 在模式级别启用所有类型的订阅

extend schema @subscription
  • 在类型级别只为特定类型启用订阅

type Movie @node @subscription {
    title: String!
}

Neo4jGraphQLSubscriptionsEngine 中移除 publish 方法

已从 Neo4jGraphQLSubscriptionsEngine 接口中移除 publish 方法,因为它不再用于基于变更数据捕获 (CDC) 的订阅。在自定义引擎上实现此方法将不再生效,并且无法再直接在 Neo4jGraphQLSubscriptionsCDCEngine 上调用 publish

连接操作现在支持相同节点之间的多个关系

连接操作已增强,支持在同一对节点之间创建多个关系。在两个节点之间执行连接操作时,即使这些节点之间已存在一个或多个相同类型的关系,也始终会创建一个新关系。这使得可以建模在相同节点之间需要多个相同类型不同关系的场景。例如,一个演员在同一部电影中扮演多个角色。

变更节点之间多重关系的行为

相同两个节点之间处理多重关系的方式已变更

  • 在实体查询字段(如 movies)中,重复节点将被移除,只返回不同的结果,无论节点之间存在多少关系。

  • 在连接查询字段(如 moviesConnection)中,所有关系都单独表示。这允许为两个节点之间的每个连接投影关系属性。

例如,考虑一个场景,艾迪·墨菲在同一部电影中扮演了多个角色

CREATE (eddie:Person {name: "Eddie Murphy"})
CREATE (nuttyProfessor:Movie { title: "The Nutty Professor" })
CREATE (eddie)-[:ACTED_IN { role: "Professor"}]->(nuttyProfessor)
CREATE (eddie)-[:ACTED_IN { role: "Buddy Love"}]->(nuttyProfessor)

使用标准实体查询

{
  actors(where: {name: {eq: "Eddie Murphy"}}) {
    name
    movies {
      title
    }
  }
}

结果只显示“肥佬教授”一次(节点已去重)

{
  "actors": [
    {
      "name": "Eddie Murphy",
      "movies": [
        {
          "title": "The Nutty Professor"
        }
      ]
    }
  ]
}

然而,使用连接查询

{
  actors(where: { name: { eq: "Eddie Murphy" } }) {
    name
    moviesConnection {
      edges {
        properties {
          role
        }
        node {
          title
        }
      }
    }
  }
}

结果保留了两个关系及其不同的属性

{
  "actors": [
    {
      "name": "Eddie Murphy",
      "moviesConnection": {
        "edges": [
          {
            "properties": {
              "role": "Professor"
            },
            "node": {
              "title": "The Nutty Professor"
            }
          },
          {
            "properties": {
              "role": "Buddy Love"
            },
            "node": {
              "title": "The Nutty Professor"
            }
          }
        ]
      }
    }
  ]
}

移除 @private 指令

此指令旨在与不再支持的库 @neo4j/graphql-ogm 一起使用。

模式生成避免冲突的复数名称

模式生成现在会检测类型中冲突的复数名称并有意失败。例如,以下模式将因模糊的 Techs 复数而失败

type Tech @node(plural: "Techs") {
    name: String
}

type Techs @node {
    value: String
}

全文搜索变更

@fulltext 指令已显著变更,现在需要索引名称、查询名称和要索引的字段

"""
Informs @neo4j/graphql that there should be a fulltext index in the database, allowing users to search by the index in the generated schema.
"""
directive @fulltext(
  indexes: [FulltextInput!]!
) on OBJECT

input FulltextInput {
  indexName: String!
  queryName: String!
  fields: [String!]!
}

以下是使用示例

type Movie @node @fulltext(
  indexes: [
    {
      indexName: "movieTitleIndex"
      queryName: "moviesByTitle"
      fields: ["title"]
    }
  ]
) {
  title: String!
}

全文搜索以前在两个不同的位置可用。以下形式已完全移除

# No longer supported
{
  movies(fulltext: { movieTitleIndex: { phrase: "The Matrix" } }) {
    title
  }
}

根级别查询已变更以使用 Relay 光标连接规范

之前 之后
query {
  moviesByTitle(phrase: "The Matrix") {
    score
    movies {
      title
    }
  }
}
query {
  moviesByTitle(phrase: "The Matrix") {
    edges {
      score
      node {
        title
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}

新形式使用 Relay 光标连接规范,该规范允许使用光标进行分页并访问 pageInfo 字段。

移除隐式设置操作

已移除更新变异中的隐式设置操作,迁移路径涉及两个步骤

之前 之后
mutation {
  updateMovies(
    where: { title: { eq: "Matrix" } },
    update: { title: "The Matrix" }
  ) {
    movies {
      title
    }
  }
}
mutation {
  updateMovies(
    where: { title: { eq: "Matrix" } },
    update: { title: { set: "The Matrix" } }
  ) {
    movies {
      title
    }
  }
}

excludeDeprecatedFieldsimplicitSet 选项已移除。

@coalesce 指令影响投影字段值

在 7.0.0 版中,@coalesce 指令现在适用于过滤操作和字段投影。以前,@coalesce 指令中指定的 fallback 值仅在这些字段用于过滤器时使用,而不用于返回的字段。现在,当您选择带有 @coalesce 注释的字段时,查询结果中的 null 值将替换为指定的 fallback 值。

考虑此模式

type Movie @node {
  title: String!
  rating: Float @coalesce(value: 5.0)
}

以前,请求一个评分为 null 的电影会返回

query {
  movies {
    title
    rating  # Would return null if the rating wasn't set
  }
}
{
  "movies": [
    {
      "title": "The Matrix",
      "rating": null
    }
  ]
}

现在,相同的查询返回聚合值

{
  "movies": [
    {
      "title": "The Matrix",
      "rating": 5.0  # Returns the fallback value specified in @coalesce
    }
  ]
}

这确保了使用 @coalesce 指令过滤和投影字段之间的一致行为。

默认将 addVersionPrefix 设置为 true

在 7.0.0 版中,addVersionPrefix 选项默认设置为 true。这意味着所有生成的 Cypher 查询都会自动添加 Cypher 版本前缀

CYPHER 5
MATCH(this:Movie)

这确保了在 Neo4j 中执行查询时使用正确的 Cypher 版本。然而,此变更可能与旧版 Neo4j 不兼容。

cypherQueryOptions.addVersionPrefix 设置为 false 以禁用此行为

{
    cypherQueryOptions: {
        addVersionPrefix: false,
    },
}

例如,使用 Apollo Server 时

await startStandaloneServer(server, {
    context: async ({ req }) => ({
        req,
        cypherQueryOptions: {
            addVersionPrefix: false,
        },
    }),
    listen: { port: 4000 },
});

变更 DateTimeTime 值转换行为

在 7.0.0 版中,DateTimeTime 值直接在生成的 Cypher 查询中从字符串转换为时间类型,而不是在使用 Neo4j 驱动程序的服务器代码中转换。

例如,如果您的 GraphQL 查询中包含日期字符串

query {
  movies(where: { releaseDate: { gt: "2023-01-15T12:30:00Z" } }) {
    title
    releaseDate
  }
}

字符串值“2023-01-15T12:30:00Z”现在直接在 Cypher 查询中转换为时间类型

MATCH (this:Movie)
WHERE this.releaseDate > datetime($param0)
RETURN this { .title, .releaseDate } as this

变异操作遵循关系方向

变异操作现在在匹配现有关系时遵守 @relationship 指令中定义的 queryDirection 值。这确保了查询和变异之间在如何遍历关系方面的一致行为。

 When creating new relationships, the physical direction stored in the database is still determined by the `direction` argument.
The change affects only how existing relationships are matched during mutation operations.

例如,考虑以下模式

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

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

queryDirection: UNDIRECTED 时,变异现在在匹配节点时沿两个方向遍历现有关系,无论基础 direction 值如何。这与查询在相同指令配置下的工作方式一致。以前,变异在匹配现有关系时总是遵循显式的 direction 值,这可能导致查询和变异之间行为不一致。

嵌套更新操作中 where 字段的位置变更

嵌套更新操作的 where 字段已被移除,取而代之的是嵌套更新输入中的 where

之前 之后
mutation {
  updateUsers(
    where: { name: { eq: "Darrell" } }
    update: {
      posts: {
        where: { node: { title: { eq: "Version 7 Release Notes" } } }
        update: { node: { title: { set: "Version 7 Release Announcement" } } }
      }
    }
  ) {
    users {
      name
      posts {
        title
      }
    }
  }
}
mutation {
  updateUsers(
    where: { name: { eq: "Darrell" } }
    update: {
      posts: {
        update: {
          where: { node: { title: { eq: "Version 7 Release Notes" } } }
          node: { title: { set: "Version 7 Release Announcement" } }
        }
      }
    }
  ) {
    users {
      name
      posts {
        title
      }
    }
  }
}

变更针对联合关系上的 singlesome 过滤器的行为

与联合类型关系一起使用 singlesome 过滤器的行为已修复,这代表了与之前不正确实现的一个重大变更。

考虑此模式,其中包含一个联合类型和与之相关的关系

union Production = Movie | Series

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

以前,在使用 singlesome 过滤器与联合类型时,这些过滤器中的条件会针对联合中的每个具体类型单独评估,要求所有类型都匹配。此行为是不正确的。

query {
    actors(
        where: {
            actedIn: { single: { Movie: { title: { contains: "The Office" } }, Series: { title: { endsWith: "Office" } } } }
        }
    ) {
        name
    }
}

7.0.0 版中的修复行为

  • single:现在正确返回在整个联合中恰好有一个相关节点的演员,而不是按类型返回。

  • some:现在正确返回在联合中至少有一个匹配的任何类型相关节点的演员。

此变更提供了更逻辑和一致的结果,但可能会影响依赖先前行为的现有查询。此修复适用于新过滤器语法和已弃用过滤器(例如 actedIn_SINGLEactedIn_SOME)。

不再支持可为空元素的列表

不再支持在带有 @node 指令注释的类型中使用可为空元素的列表,例如以下类型定义中

type Actor @node {
  name: String
  pseudonyms: [String]!
}

这是因为 Neo4j 不支持将 null 值作为列表的一部分存储。要创建类似但受支持的类型定义,请将 pseudonyms 字段的值更改为非空列表:[String!]!

接口和联合不允许混合带或不带 @node 指令的类型

接口和联合只能由全部带有 @node 指令或全部不带 @node 指令的类型实现。

以下类型定义不再受支持,因为 Series 类型缺少 @node 指令

interface Production @node {
  title: String
}
type Movie @node implements Production {
  title: String
}
type Series implements Production {
  title: String
}

关系字段需要 @node 类型

@relationship 指令只能应用于其类型带有 @node 指令注释的字段。

这也适用于定义为接口和联合的字段,这些字段必须仅由 @node 类型实现。

弃用

弃用专用输入外部的变异运算符

以下运算符现已弃用

  • _SET

  • _POP

  • _PUSH

  • _INCREMENT

  • _ADD

  • _DECREMENT

  • _SUBTRACT

  • _MULTIPLY

  • _DIVIDE

请改用专用输入对象版本

之前 之后
mutation {
  updateMovies(
    where: { title: { eq: "Matrix" } },
    update: { title_SET: "The Matrix" }
  ) {
    movies {
      title
    }
  }
}
mutation {
  updateMovies(
    where: { title: { eq: "Matrix" } },
    update: { title: { set: "The Matrix" }  }
  ) {
    movies {
      title
    }
  }
}

excludeDeprecatedFields 选项现在包含 mutationOperations 选项,用于移除这些已弃用的运算符

const neoSchema = new Neo4jGraphQL({
  typeDefs,
  excludeDeprecatedFields: {
    mutationOperations: true
  }
});

弃用 _EQ 过滤器语法

_EQ 过滤器语法现已弃用。请改用专用输入对象版本

之前 之后
{
  movies(where: { title_EQ: "The Matrix" }) {
    title
  }
}
{
  movies(where: { title: { eq: "The Matrix" } }) {
    title
  }
}

excludeDeprecatedFields 选项现在包含 attributeFilters 选项,用于移除这些已弃用的过滤器

const neoSchema = new Neo4jGraphQL({
  typeDefs,
  excludeDeprecatedFields: {
    attributeFilters: true
  }
});

弃用连接字段外部的聚合过滤器

连接字段外部的聚合过滤器现已弃用。请改用连接输入字段内的聚合过滤器

之前 之后
{
    posts(where: { likesAggregate: { node: { someInt: { average: { eq: 10 } } } } }) {
        content
    }
}
{
    posts(where: { likesConnection: { aggregate: { node: { someInt: { average: { eq: 10 } } } } } }) {
        content
    }
}

excludeDeprecatedFields 选项现在包含 aggregationFiltersOutsideConnection 选项,用于移除这些已弃用的过滤器

const neoSchema = new Neo4jGraphQL({
  typeDefs,
  excludeDeprecatedFields: {
    aggregationFiltersOutsideConnection: true
  }
});

弃用专用输入外部的聚合过滤器

专用输入外部的聚合过滤器(如 _AVERAGE_GT)现已弃用。请改用专用输入对象版本

之前 之后
query Movies {
  movies(
    where: { actorsAggregate: { node: { lastRating_AVERAGE_GT: 6 } } }
  ) {
    title
  }
}
query Movies {
  movies(
    where: {
      actorsAggregate: { node: { lastRating: { average: { gt: 6 } } } }
    }
  ) {
    title
  }
}

excludeDeprecatedFields 选项现在包含 aggregationFilters 选项,用于移除这些已弃用的过滤器

const neoSchema = new Neo4jGraphQL({
  typeDefs,
  excludeDeprecatedFields: {
    aggregationFilters: true
  }
});

弃用专用输入外部的关系过滤器

专用输入外部的关系过滤语法(如 _SOME_ALL_NONE)现已弃用。请改用专用输入对象版本

之前 之后
{
  movies(where: { actors_SOME: { name_EQ: "Keanu Reeves" } }) {
    title
  }
}
{
  movies(where: { actors: { some: { name: { eq: "Keanu Reeves" } } } }) {
    title
  }
}

excludeDeprecatedFields 选项现在包含 relationshipFilters 选项,用于移除这些已弃用的过滤器

const neoSchema = new Neo4jGraphQL({
  typeDefs,
  excludeDeprecatedFields: {
    relationshipFilters: true
  }
});
© . All rights reserved.