迁移至 7.0.0
|
这是 GraphQL Library 7 版本的文档。对于长期支持 (LTS) 版本 5,请参考 GraphQL Library 5 LTS 版本。 |
本页面列出了从 Neo4j GraphQL Library 6.x 到 7.x 的所有重大变更以及升级方法。
重大变更
以下是从 6.0.0 到 7.0.0 的所有重大变更列表。
移除隐式过滤字段
隐式相等过滤字段已被移除。请改用专门的 eq 字段。
| 之前 | 之后 |
|---|---|
|
|
excludeDeprecatedFields 中的 implicitEqualFilters 选项已被移除。
必需的 @node 指令
现在强制要求使用 @node 指令。没有 @node 指令的 GraphQL 对象类型不再被视为 Neo4j 节点表示。仅针对具有 @node 指令的类型生成查询和变更。
| 之前 | 之后 |
|---|---|
|
|
移除已弃用的 options 参数
已弃用的 options 参数已被移除。
考虑以下类型定义
type Movie @node {
title: String!
}
以下展示了 options 的差异
| 之前 | 之后 |
|---|---|
|
|
excludeDeprecatedFields 中的 deprecatedOptionsArgument 选项已被移除。
移除已弃用的 directed 参数
查询中已弃用的 directed 参数已被移除。该参数此前允许在查询时指定关系是有向的还是无向的。现在请改用 @relationship 指令中的 queryDirection 参数。
excludeDeprecatedFields 中的 directedArgument 选项已被移除。
更改了 @relationship 中 queryDirection 参数的可接受值
随着 directed 参数的移除,@relationship 指令的 queryDirection 参数现在仅接受两个值
-
DIRECTED(默认) -
UNDIRECTED
以下值不再受支持
-
DEFAULT_DIRECTED -
DEFAULT_UNDIRECTED -
DIRECTED_ONLY -
UNDIRECTED_ONLY
移除已弃用的 typename_IN 过滤器
已弃用的 typename_IN 过滤器已被移除。请改用 typename。
| 之前 | 之后 |
|---|---|
|
|
excludeDeprecatedFields 中的 typename_IN 选项已被移除。
移除单一元素关系
单一元素关系已被移除,转而支持列表关系。
| 之前 | 之后 |
|---|---|
|
|
单一元素关系无法被可靠地强制执行,导致数据与架构不一致。如果 GraphQL 模型需要一对一关系(例如在联合体中),现在可以使用 @cypher 指令来创建。
type Movie @node {
director: Person
@cypher(
statement: """
MATCH (this)-[:ACTED_IN]->(p:Person)
RETURN p
"""
columnName: "p"
)
}
移除连接操作中的 overwrite 参数
连接操作中的 overwrite 参数已被移除。
在 7.0.0 版本中,连接操作已被简化,始终在节点之间创建新关系,无论该关系是否已经存在。请参阅 连接操作现在支持在相同节点之间创建多个关系。
如果你必须更新现有关系而不是创建新关系,请使用 update 操作。
mutation {
updateMovies(
update: {
actors: [
{
where: { node: { name: { eq: "Keanu" } } }
update: { edge: { role: { set: "Neo" } } }
}
]
}
) {
movies {
title
}
}
}
移除连接字段之外的聚合字段
已弃用的聚合字段已从架构中移除。请改用连接选择集内的聚合字段。
| 之前 | 之后 |
|---|---|
|
|
excludeDeprecatedFields 设置中已移除 deprecatedAggregateOperations 选项。
订阅现在需要明确选择 (Opt-in)
订阅不再自动为所有 @node 类型生成。在 7.x 版本中,必须使用 @subscription 指令来启用此功能。现在你必须通过以下两种方式之一明确启用订阅:
-
在架构级别启用所有类型的订阅
extend schema @subscription
-
在类型级别仅为特定类型启用订阅
type Movie @node @subscription {
title: String!
}
从 Neo4jGraphQLSubscriptionsEngine 移除 publish 方法
publish 方法已从 Neo4jGraphQLSubscriptionsEngine 接口中移除,因为它不再用于基于变更数据捕获 (CDC) 的订阅。在自定义引擎上实现此方法将不再产生任何效果,也无法再直接在 Neo4jGraphQLSubscriptionsCDCEngine 上调用 publish。
连接操作现在支持在相同节点之间创建多个关系
连接操作已增强,支持在同一对节点之间创建多个关系。在执行两个节点之间的连接操作时,始终会创建一个新关系,即使节点之间已经存在一种或多种相同类型的关系。这使得建模场景可以支持在相同节点之间需要多个不同关系的情况。例如,演员在同一部电影中扮演多个角色。
更改了在节点之间存在多个关系时的处理行为
在相同两个节点之间处理多个关系的方式发生了变化:
-
在实体查询字段(如
movies)中,重复的节点会被移除,仅返回不同结果,无论节点之间存在多少个关系。 -
在连接查询字段(如
moviesConnection)中,所有关系都会被单独表示。这允许为两个节点之间的每个连接投影关系属性。
例如,考虑 Eddie Murphy 在同一部电影中扮演多个角色的场景:
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
}
}
}
结果显示 "The Nutty Professor" 仅一次(节点已去重)
{
"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"
}
}
]
}
}
]
}
架构生成避免冲突的复数名称
架构生成现在会检测类型中冲突的复数名称并故意报错。例如,由于 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 Cursor Connections 规范
| 之前 | 之后 |
|---|---|
|
|
新形式使用 Relay Cursor Connections 规范,允许使用游标进行分页,并可以访问 pageInfo 字段。
移除隐式设置 (set) 操作
更新变更中的隐式设置操作已被移除,迁移路径涉及两个步骤。
| 之前 | 之后 |
|---|---|
|
|
excludeDeprecatedFields 中的 implicitSet 选项已被移除。
@coalesce 指令影响投影字段值
在 7.0.0 版本中,@coalesce 指令现在同时应用于过滤操作和字段投影。此前,@coalesce 指令中指定的备用值仅在这些字段用于过滤器时使用,而在返回字段时不使用。现在,当你选择一个带有 @coalesce 注解的字段时,空值会在查询结果中被指定的备用值替换。
考虑此架构
type Movie @node {
title: String!
rating: Float @coalesce(value: 5.0)
}
此前,请求评分为空的电影将返回:
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 },
});
更改了 DateTime 和 Time 值转换行为
在 7.0.0 版本中,DateTime 和 Time 值直接在生成的 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。
| 之前 | 之后 |
|---|---|
|
|
更改了关系对联合类型的 single 和 some 过滤器的行为
当与联合类型建立关系时,single 和 some 过滤器的行为已修复,这构成了与先前错误实现相比的重大变更。
考虑这个带有联合类型及其关系的架构
union Production = Movie | Series
type Actor @node {
name: String!
actedIn: [Production!]! @relationship(type: "ACTED_IN", direction: OUT)
}
此前,当对联合使用 single 或 some 过滤器时,过滤器内的条件会对联合中的每个具体类型分别评估,要求所有类型都匹配。这种行为是错误的。
query {
actors(
where: {
actedIn: { single: { Movie: { title: { contains: "The Office" } }, Series: { title: { endsWith: "Office" } } } }
}
) {
name
}
}
7.0.0 版本中的修复行为:
-
single:现在正确返回在整个联合中只有一个相关节点的参与者,而不是按类型计算。 -
some:现在正确返回在联合中至少有一个匹配的相关节点的参与者。
此更改提供了更符合逻辑和一致的结果,但可能会影响依赖先前行为的现有查询。此修复同时适用于新过滤器语法和已弃用的过滤器(例如 actedIn_SINGLE 和 actedIn_SOME)。
不再支持可为空元素的列表
在带有 @node 注解的类型中,不再支持可为空元素的列表。例如在以下类型定义中:
type Actor @node {
name: String
pseudonyms: [String]!
}
这是因为 Neo4j 不支持将 null 值存储在列表中。要创建类似但受支持的类型定义,请将 pseudonyms 字段的值更改为非空列表:[String!]!。
弃用说明
弃用了专用输入之外的变更操作符
以下操作符现已弃用:
-
_SET -
_POP -
_PUSH -
_INCREMENT -
_ADD -
_DECREMENT -
_SUBTRACT -
_MULTIPLY -
_DIVIDE
请改用专用输入对象版本。
| 之前 | 之后 |
|---|---|
|
|
excludeDeprecatedFields 选项现在包含 mutationOperations 选项,用于移除这些已弃用的操作符。
const neoSchema = new Neo4jGraphQL({
typeDefs,
excludeDeprecatedFields: {
mutationOperations: true
}
});
弃用了 _EQ 过滤语法
_EQ 过滤语法现已弃用。请改用专用输入对象版本。
| 之前 | 之后 |
|---|---|
|
|
excludeDeprecatedFields 选项现在包含 attributeFilters 选项,用于移除这些已弃用的过滤器。
const neoSchema = new Neo4jGraphQL({
typeDefs,
excludeDeprecatedFields: {
attributeFilters: true
}
});
弃用了连接字段之外的聚合过滤器
连接字段之外的聚合过滤器现已弃用。请改用连接输入字段内的聚合过滤器。
| 之前 | 之后 |
|---|---|
|
|
excludeDeprecatedFields 选项现在包含 aggregationFiltersOutsideConnection 选项,用于移除这些已弃用的过滤器。
const neoSchema = new Neo4jGraphQL({
typeDefs,
excludeDeprecatedFields: {
aggregationFiltersOutsideConnection: true
}
});
弃用了专用输入之外的聚合过滤器
像 _AVERAGE_GT 这样在专用输入之外的聚合过滤器现已弃用。请改用专用输入对象版本。
| 之前 | 之后 |
|---|---|
|
|
excludeDeprecatedFields 选项现在包含 aggregationFilters 选项,用于移除这些已弃用的过滤器。
const neoSchema = new Neo4jGraphQL({
typeDefs,
excludeDeprecatedFields: {
aggregationFilters: true
}
});
弃用了专用输入之外的关系过滤器
像 _SOME, _ALL, 和 _NONE 这样在专用输入之外的关系过滤语法现已弃用。请改用专用输入对象版本。
| 之前 | 之后 |
|---|---|
|
|
excludeDeprecatedFields 选项现在包含 relationshipFilters 选项,用于移除这些已弃用的过滤器。
const neoSchema = new Neo4jGraphQL({
typeDefs,
excludeDeprecatedFields: {
relationshipFilters: true
}
});