过滤
本页面介绍如何在 Neo4j GraphQL 库中对订阅应用过滤器。但请注意,
-
过滤只能应用于订阅操作的根节点。
-
不支持订阅类型的聚合,目前没有可用方法。
可以创建订阅来针对节点 (create
/update
/delete
) 或关系 (create
/delete
) 的更改。
虽然格式略有不同,取决于订阅是针对节点还是关系,但提供 where
参数允许对返回给订阅的事件进行过滤。
订阅节点事件
where
参数允许指定针对目标节点的顶层属性的过滤器。仅与这些属性和类型匹配的事件将返回给订阅。
例如,请考虑以下类型定义
type Movie {
title: String
genre: String
averageRating: Float
releasedIn: Int
}
现在,以下是创建订阅时如何应用过滤器的示例
CREATE
要过滤对电影的 create
操作的订阅(按其类型进行过滤),请执行以下操作
subscription {
movieCreated(where: {genre: "Drama"}) {
createdMovie {
title
}
}
}
这样,只有新创建的类型为 "Drama"
的电影才会将事件触发到此订阅。
|
UPDATE
以下是过滤对平均评分大于 8 的电影的 update
操作的订阅的示例
subscription {
movieUpdate(where: {averageRating_GT: 8}) {
updatedMovie {
title
}
}
}
这样,只有当修改平均评分大于 8 的电影时,您才会收到由这些电影触发的事件。
|
这些事件可能如下所示
mutation {
makeTheMatrix: createMovies(input: {title: "The Matrix", averageRating: 8.7}) {
title
averageRating
},
makeResurrections: createMovies(input: {title: "The Matrix Resurrections", averageRating: 5.7}) {
title
averageRating
},
}
mutation {
updateTheMatrix: updateMovie(
where: {title: "The Matrix"}
update: {averageRating: 7.9}
) {
title
},
updateResurrections: updateMovie(
where: {title: "The Matrix Resurrections"}
update: {averageRating: 8.9}
) {
title
}
}
因此,鉴于之前描述的订阅,这些 GraphQL 操作应仅针对 "The Matrix"
电影触发。
DELETE
以下是过滤对电影的 delete
操作的订阅的示例,方法是使用 NOT
过滤器按其类型进行过滤
subscription {
movieDeleted(where: { NOT: { genre: "Comedy" } }) {
deletedMovie {
title
}
}
}
这样,只有所有类型(除 "Comedy"
之外)的已删除电影才会将事件触发到此订阅。
|
组合运算符
所有前面提到的运算符都可以使用 AND
、OR
和 NOT
运算符组合起来。它们接受一个参数,该参数是与 where
参数格式相同的项目的数组,这意味着它们也可以嵌套以形成复杂的组合。
例如,考虑一个喜欢喜剧电影,但不喜欢 2000 年初的浪漫喜剧,并且将黑客帝国三部曲作为他们最喜欢的电影的用户。他们可以订阅以下涵盖这组特定兴趣的任何更新
subscription {
movieUpdated(where: {
OR: [
{ title_CONTAINS: "Matrix" },
{ genre: "comedy" },
{ AND: [
{ NOT: { genre: "romantic comedy" } },
{ releasedIn_GT: 2000 },
{ releasedIn_LTE: 2005 }
] },
]
}) {
updatedMovie {
title
}
}
}
订阅关系事件
在订阅关系事件时,where
参数仍然允许指定针对目标节点的顶层属性的过滤器。它还支持指定针对关系属性 (edge
) 和关系另一端节点的顶层属性 (node
) 的过滤器。这可以通过使用前面描述的运算符来完成,其用法与 订阅节点事件 非常相似。
但是,通过关系事件进行过滤是一种更强大的逻辑。这是因为这些过滤器还可以表达预期的关系字段,或者关系另一端的预期具体类型(假设它们连接到抽象类型)。
请注意,每个指定的关联字段都与其他关联字段使用 逻辑 OR
组合。订阅中仅返回与这些关系字段名称匹配的事件。
您可以进一步通过节点和关系属性过滤每个关系字段。这些字段在生成的过滤器中使用 逻辑 AND
组合在一起。
例如,在以下类型定义中
type Movie {
title: String
genre: String
actors: [Actor!]! @relationship(type: "ACTED_IN", properties: "ActedIn", direction: IN)
}
type ActedIn @relationshipProperties {
screenTime: Int!
}
type Actor {
name: String
}
where
参数的格式为
{
movie: {
# top-level properties of the node targeted for the subscription operation, supports operators
title_IN: ["The Matrix", "Fight Club"]
},
createdRelationship: {
actors: { # field name corresponding to a relationship in the type definition of the node targeted for the subscription operation
edge: {
# properties of the relationship, supports operators
screenTime_GT: 10,
},
node: {
# top-level properties of the node on the other end of the relationship, supports operators
name_STARTS_WITH: "Brad"
}
}
}
}
以下部分介绍了在创建对关系事件的订阅时如何应用过滤器的示例。
新创建的关系
以下示例过滤了对新创建关系的订阅,这些关系将来自除“剧情片”以外类型的电影连接到屏幕时间超过 10 分钟的演员。
subscription {
movieRelationshipCreated(where: { movie: { NOT: { genre: "Drama" } }, createdRelationship: { actors: { edge: { screenTime_GT: 10 } } } }) {
movie {
title
}
createdRelationship {
actors {
screenTime
node {
name
}
}
}
}
}
|
新删除的关系
以下示例过滤了对已删除关系的订阅,这些关系将类型为“喜剧片”或“冒险片”的电影连接到名为“金·凯瑞”的演员。
subscription {
movieRelationshipDeleted(where: { movie: { genre_IN: ["Comedy", "Adventure"] }, createdRelationship: { actors: { node: { name: "Jim Carrey" } } } }) {
movie {
title
}
deletedRelationship {
actors {
screenTime
node {
name
}
}
}
}
}
|
与关系相关的过滤器
除了过滤节点或关系属性之外,与关系相关的过滤逻辑更强大。这是因为这些过滤器还可以表示预期关系字段,或关系另一端预期的具体类型,前提是它们连接到抽象类型。
以下示例适用于 CREATE_RELATIONSHIP
和 DELETE_RELATIONSHIP
事件。它们的目的是说明订阅关系事件的各种过滤方式。
考虑以下类型定义
type Movie {
title: String
genre: String
actors: [Actor!]! @relationship(type: "ACTED_IN", properties: "ActedIn", direction: IN)
directors: [Director!]! @relationship(type: "DIRECTED", properties: "Directed", direction: IN)
reviewers: [Reviewer!]! @relationship(type: "REVIEWED", properties: "Review", direction: IN)
}
type ActedIn @relationshipProperties {
screenTime: Int!
}
type Actor {
name: String
}
type Person implements Reviewer {
name: String
reputation: Int
}
union Director = Person | Actor
type Directed @relationshipProperties {
year: Int!
}
interface Reviewer {
reputation: Int!
}
type Magazine implements Reviewer {
title: String
reputation: Int!
}
type Review @relationshipProperties {
score: Int!
}
以及基本的订阅操作
subscription MovieRelationshipDeleted($where: MovieRelationshipDeletedSubscriptionWhere) {
movieRelationshipDeleted(where: $where) {
movie {
title
}
deletedRelationship {
actors {
screenTime
node {
name
}
}
directors {
year
node {
... on PersonEventPayload { # generated type
name
reputation
}
... on ActorEventPayload { # generated type
name
}
}
}
reviewers {
score
node {
reputation
... on MagazineEventPayload { # generated type
title
reputation
}
... on PersonEventPayload { # generated type
name
reputation
}
}
}
}
}
}
您可以使用以下 where
输入在 GraphQL 变量值中获取不同的结果
通过隐式/显式声明进行过滤
隐式或显式声明用于过滤预期返回给订阅的特定关系类型。
例如,当订阅到电影的已创建或已删除关系时,用户可能只对 ACTED_IN
类型的关系感兴趣,但对演员节点的属性或连接到它的其他关系不感兴趣。在这种情况下,此关系的对应字段名为 actors
。
通过显式指定 actors
字段名,您可以过滤掉对其他关系属性的事件
{
where: {
deletedRelationship: {
actors: {} # no properties specified here, therefore all relationships to this field name will be returned
}
}
}
如果您对符合某些过滤器(例如,名称以字母“A”开头的)的演员节点感兴趣,则过程与 订阅节点事件 没有区别
{
where: {
deletedRelationship: {
actors: {
node: { # use operations to specify filers on the top-level properties of the node at the other end of the relationship
name_STARTS_WITH: "A"
}
}
}
}
}
如果您也对关系本身符合某些过滤器感兴趣,例如演员在电影中的时间不超过 40 分钟,则查询可能如下所示
{
where: {
deletedRelationship: {
actors: {
edge: { # use operations to specify filers on the top-level properties of the relationship
screenTime_LT: 40,
}
node: {
name: "Alvin"
}
}
}
}
}
通过显式指定相应的字段名,还可以将多种关系类型包含在返回的订阅中。例如
{
where: {
deletedRelationship: {
actors: {}, # include all relationships corresponding of type `ACTED_IN`
directors: {} # include all relationships corresponding of type `DIRECTED`
# exclude relationships of type `REVIEWED`
}
}
}
现在,如果您对所有关系类型感兴趣,您可以通过不指定任何内容来隐式表示此关系
{
where: {
deletedRelationship: {} # include all relationships of all types
}
}
或者通过显式指定连接到目标订阅类型的字段名来进行显式表示
{
where: {
deletedRelationship: {
# include all relationships of all types
# subscription target type is `Movie`, which has the following relationship field names:
actors: {},
directors: {},
reviewers: {}
}
}
}
但是,请注意,由于对任何关系应用了任何过滤器,因此显式包含您希望订阅的关系是强制性的步骤。
例如,如果应该返回所有关系,但您希望过滤掉得分低于 7 的 REVIEWED
关系,则您的查询可能如下所示
{
where: {
deletedRelationship: {
actors: {}, # include all relationships of type `ACTED_IN`
directors: {}, # include all relationships of type `DIRECTED`
reviewers: { # include all relationships of type `REVIEWED`, with the score property greater than 7
edge: {
score_GT: 7
}
}
}
}
}
不同的过滤器也可以应用于不同的关系,没有任何限制。例如
{
where: {
deletedRelationship: {
actors: { # include some relationships of type `ACTED_IN`, filtered by relationship property `screenTime` and node property `name`
edge: {
screenTime_LT: 60,
},
node: {
name_IN: ["Tom Hardy", "George Clooney"]
}
},
directors: {}, # include all relationships of type `DIRECTED`
reviewers: { # include some relationships of type `REVIEWED`, filtered by relationship property `score` only
edge: {
score_GT: 7
}
}
}
}
}
在前面的示例中, |
在 |
抽象类型
以下部分描述了如何使用抽象类型过滤订阅。
联合类型
本示例说明了如何过滤关系另一端节点,当该节点为联合类型时
{
where: {
deletedRelationship: {
directors: { # relationship to a union type
Person: { # concrete type that makes up the union type
edge: {
year_GT: 2010
},
node: {
name: "John Doe",
reputation: 10
}
},
Actor: { # concrete type that makes up the union type
edge: {
year_LT: 2005
},
node: {
name: "Tom Hardy"
}
}
},
}
}
}
结果是,只有 DIRECTED
类型的关系返回给订阅,其中导演为名为“John Doe”的 Person,他在 2010 年之后执导了电影,或者导演为名为“Tom Hardy”的 Actor,他在 2005 年之前执导了电影。
请注意,关系字段名被分成多个部分,每个部分对应于构成联合类型的具体类型之一。关系属性不存在于这些部分之外,即使属性相同。
现在,考虑另一个没有显式指定具体类型的示例
{
where: {
deletedRelationship: {
directors: {}, # include all relationships of type `DIRECTED`
}
}
}
遵循与关系字段名相同的逻辑:当没有明确提供任何内容时,则接受所有内容。因此,类型为 DIRECTED
且在电影和构成联合类型 Director
的任何具体类型之间建立的关系将返回给订阅。
它等效于以下内容
{
where: {
deletedRelationship: {
directors: { # include all relationships of type `DIRECTED`
Actor: {},
Person: {}
}
}
}
}
请注意,显式指定具体类型会将其他类型从返回的事件中排除
{
where: {
deletedRelationship: {
directors: {
Actor: {} # include all relationships of type `DIRECTED` to an `Actor` type
}
}
}
}
在这种情况下,只有电影和演员之间类型为 DIRECTED
的关系会返回给订阅。电影和 Person 之间的关系被过滤掉。
这样做的一种原因是,在 Actor 类型上包含一些过滤器
{
where: {
deletedRelationship: {
directors: {
Actor: { # include some relationships of type `DIRECTED` to an `Actor` type, that conform to the filters
node: {
NOT: { name: "Tom Hardy" }
}
}
}
}
}
}
要包含 Actor 类型上的过滤器,但也要将 Person 类型包含在结果中,您需要明确说明意图
{
where: {
deletedRelationship: {
directors: {
Actor: { # include some relationships of type `DIRECTED` to an `Actor` type, that conform to the filters
node: {
NOT: { name: "Tom Hardy" }
}
},
Person: {} # include all relationships of type `DIRECTED` to a `Person` type
}
}
}
}
接口类型
以下示例说明了如何过滤关系另一端节点,当该节点为接口类型时
{
where: {
deletedRelationship: {
reviewers: { # relationship to an interface type
edge: {
# relationship properties of a relationship of type `REVIEWED`
score_GT: 7
},
node: {
# common fields declared by the interface
reputation_GTE: 8
}
},
}
}
}
本示例返回类型为 Movie
和 Reviewer
之间关系的事件,其中得分高于 7,并且 Reviewer
的信誉大于或等于 7。