Skip to content

Commit a05a461

Browse files
authored
Merge pull request #180 from neo4j/updates-to-filtering-page
Updates to filtering page
2 parents 302fd38 + 6ca8de4 commit a05a461

File tree

1 file changed

+160
-99
lines changed

1 file changed

+160
-99
lines changed

modules/ROOT/pages/queries-aggregations/filtering.adoc

Lines changed: 160 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,51 @@
33
:page-aliases: filtering.adoc
44
:description: This page describes filtering operators.
55

6-
When querying for data, a number of operators are available for different types in the `where` argument of a query or mutation.
6+
When querying for data, a number of operators are available for the types in the `where` argument of a query or mutation, allowing you to filter query results or specify the set of objects a mutation applies to.
77

8-
== Equality operators
8+
Operators can either be standalone operators (see xref:#_boolean_operators[]) or they are appended to field names (for example, xref:/queries-aggregations/filtering.adoc#_string_comparison[]).
9+
10+
All operators can be combined using the Boolean operators `AND`, `OR`, and `NOT`.
11+
12+
== Operators
13+
14+
=== Boolean operators
15+
16+
As standalone operators, Boolean operators accept an array argument with items of the same format as the `where` argument.
17+
This way, they can be nested to form complex Boolean expressions.
18+
19+
For example, if you want to match all actors either by the name of "Keanu" or not belonging to the "Pantoliano" family, who played in "The Matrix" movie, here is how you query that:
20+
21+
[source, graphql, indent=0]
22+
----
23+
query {
24+
actors(where: {
25+
AND: [
26+
{
27+
OR: [
28+
{ name_CONTAINS: "Keanu" },
29+
{ NOT: { name_ENDS_WITH: "Pantoliano" } }
30+
]
31+
},
32+
{
33+
movies_SOME: { title: "The Matrix" }
34+
}
35+
]}
36+
) {
37+
name
38+
movies {
39+
title
40+
}
41+
}
42+
}
43+
----
44+
45+
`name_CONTAINS` and `name_ENDS_WITH` are xref:/queries-aggregations/filtering.adoc#_string_comparison[String comparisons] while `movies_SOME` is a xref:/queries-aggregations/filtering.adoc#_relationship_filtering[relationship filter].
46+
47+
=== Equality operators
48+
49+
All types can be tested for equality or non-equality.
950

10-
All types can be tested for either equality.
11-
For non-equality, you *must* use the xref:/queries-aggregations/filtering.adoc#_logical_operators[`NOT`] logical operator.
1251
For example:
1352

1453
.Filtering all users named John
@@ -21,12 +60,24 @@ query {
2160
}
2261
----
2362

63+
For non-equality, you must use the xref:/queries-aggregations/filtering.adoc#_boolean_operators[`NOT`] logical operator.
64+
65+
.Filtering all users which are not named John
66+
[source, graphql, indent=0]
67+
----
68+
query {
69+
users(where: { NOT: {name: "John" }})
70+
id
71+
name
72+
}
73+
----
74+
2475
[NOTE]
2576
====
2677
For the `Boolean` type, equality operators are the only ones available.
2778
====
2879

29-
== Numerical operators
80+
=== Numerical operators
3081

3182
These are the operators available for numeric (`Int`, `Float`, xref::/types/scalar.adoc[`BigInt`]), xref::/types/temporal.adoc[temporal] and xref::/types/spatial.adoc[spatial] types:
3283

@@ -52,43 +103,72 @@ query {
52103
Spatial types use numerical filtering differently and they also have additional options.
53104
See xref:filtering.adoc#_filtering_spatial_types[Filtering spatial types] for more information.
54105

55-
== Logical operators
106+
==== Spatial type filtering
56107

57-
All operators can be combined using the logical operators `AND`, `OR`, and `NOT`.
58-
They can also be standalone operators, which means that they can be used as such and not be appended to field names.
108+
Both the `Point` and the `CartesianPoint` types use xref::queries-aggregations/filtering.adoc#_numerical_operators[numerical operators] and have an additional `_DISTANCE` filter.
109+
Here is a list of what each filter does for the two types:
59110

60-
These operators accept an array argument with items of the same format as the `where` argument, which means they can also be nested to form complex combinations.
111+
* `_LT`: checks if a point is less than the distance in the `distance` field away (in meters) from the point specified by the `point` field.
112+
* `_LTE`: checks if a point is less than or equal to the distance in the `distance` field away (in meters) from the point specified by the `point` field.
113+
* `_DISTANCE`: checks if a point is the exact distance in the `distance` field away (in meters) from the point specified by the `point` field.
114+
* `_GT`: checks if a point is greater than the distance in the `distance` field away (in meters) from the point specified by the `point` field.
115+
* `_GTE`: checks if a point is greater than or equal to the distance in the `distance` field away (in meters) from the point specified by the `point` field.
61116

62-
For example, if you want to match all actors by the name of either "Keanu" or not belonging to the "Pantoliano" family, that played in "The Matrix" movie, here is how you can query that:
117+
For a `Point` type, all filters take the following type as an argument:
63118

64119
[source, graphql, indent=0]
65120
----
66-
query {
67-
actors(where: {
68-
AND: [
69-
{
70-
OR: [
71-
{ name_CONTAINS: "Keanu" },
72-
{ NOT: { name_ENDS_WITH: "Pantoliano" } }
73-
]
74-
},
75-
{
76-
movies_SOME: { title: "The Matrix" }
77-
}
78-
]}
79-
) {
121+
input PointDistance {
122+
point: Point!
123+
distance: Float!
124+
}
125+
----
126+
127+
In practice, you can construct queries like the following, which finds all users within a 5km (5000m) radius of a `Point`:
128+
129+
[source, graphql, indent=0]
130+
----
131+
query CloseByUsers($longitude: Float!, $latitude: Float!) {
132+
users(where: { location_LTE: { point: { longitude: $longitude, latitude: $latitude }, distance: 5000 } }) {
80133
name
81-
movies {
82-
title
134+
location {
135+
longitude
136+
latitude
83137
}
84138
}
85139
}
86140
----
87141

142+
Similarly, for a `CartesianPoint` type, all filters take the following type as an argument:
88143

89-
== String comparison
144+
[source, graphql, indent=0]
145+
----
146+
input CartesianPointDistance {
147+
point: CartesianPoint!
148+
distance: Float!
149+
}
150+
----
90151

91-
The following case-sensitive comparison operators are only available for use on `String` and `ID` types:
152+
The same query for a `CartesianPoint`:
153+
154+
[source, graphql, indent=0]
155+
----
156+
query CloseByUsers($x: Float!, $y: Float!) {
157+
users(where: { location_LTE: { point: { x: $x, y: $y }, distance: 5000 } }) {
158+
name
159+
location {
160+
x
161+
y
162+
}
163+
}
164+
}
165+
----
166+
167+
== Type comparison
168+
169+
=== String comparison
170+
171+
The following case-sensitive comparison operators are available for `String` and `ID` types:
92172

93173
* `_STARTS_WITH`
94174
* `_ENDS_WITH`
@@ -141,16 +221,17 @@ const features = {
141221
const neoSchema = new Neo4jGraphQL({ features, typeDefs, driver });
142222
----
143223

144-
== RegEx matching
224+
=== RegEx matching
145225

146-
The filter `_MATCHES` is also available for comparison of `String` and `ID` types.
226+
The filter `_MATCHES` is available for comparison of `String` and `ID` types.
147227
It accepts RegEx strings as an argument and returns any matches.
148228

149-
150-
Note that RegEx matching filters are **disabled by default**.
229+
Note that RegEx matching filters are disabled by default.
151230
This is because, on an unprotected API, they could potentially be used to execute a https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS[ReDoS attack^] against the backing Neo4j database.
152231

153-
If you want to enable them, set the features configuration object for each:
232+
If you want to enable RegEx matching, update the `features` configuration object.
233+
234+
For `String`:
154235

155236
[source, javascript, indent=0]
156237
----
@@ -172,8 +253,8 @@ For `ID`:
172253
----
173254
const features = {
174255
filters: {
175-
String: {
176-
ID: true,
256+
ID: {
257+
MATCHES: true,
177258
}
178259
}
179260
};
@@ -183,7 +264,6 @@ const neoSchema = new Neo4jGraphQL({ features, typeDefs, driver });
183264

184265
For both `String` and `ID`:
185266

186-
187267
[source, javascript, indent=0]
188268
----
189269
const features = {
@@ -200,96 +280,74 @@ const features = {
200280
const neoSchema = new Neo4jGraphQL({ features, typeDefs, driver });
201281
----
202282

203-
== Array comparison
204-
205-
The following operator is available on non-array fields, and accepts an array argument:
206-
207-
* `_IN`
208-
209-
Conversely, the following operator is available on array fields, and accepts a single argument:
210-
211-
* `_INCLUDES`
212-
213-
These operators are available for all types apart from `Boolean`.
214-
215-
== Filtering spatial types
283+
=== Array comparison
216284

217-
Both the `Point` and the `CartesianPoint` types use xref::queries-aggregations/filtering.adoc#_numerical_operators[numerical operators] and have an additional `_DISTANCE` filter.
218-
Here is a list of what each filter does for the two types:
219-
220-
* `_LT`: checks if a point is less than the distance in the `distance` field away (in meters) from the point specified by the `point` field.
221-
* `_LTE`: checks if a point is less than or equal to the distance in the `distance` field away (in meters) from the point specified by the `point` field.
222-
* `_DISTANCE`: checks if a point is the exact distance in the `distance` field away (in meters) from the point specified by the `point` field.
223-
* `_GT`: checks if a point is greater than the distance in the `distance` field away (in meters) from the point specified by the `point` field.
224-
* `_GTE`: checks if a point is greater than or equal to the distance in the `distance` field away (in meters) from the point specified by the `point` field.
225-
226-
For a `Point` type, all filters take the following type as an argument:
285+
Consider the following type definitions:
227286

228287
[source, graphql, indent=0]
229288
----
230-
input PointDistance {
231-
point: Point!
232-
distance: Float!
289+
type Movie {
290+
id: ID!
291+
title: String!
292+
genres: [String!]
293+
year: Int!
294+
actors: [Actor!]! @relationship(type: "ACTED_IN", direction: IN)
233295
}
234-
----
235-
236-
In practice, you can construct queries like the following, which finds all users within a 5km (5000m) radius of a `Point`:
237296
238-
[source, graphql, indent=0]
239-
----
240-
query CloseByUsers($longitude: Float!, $latitude: Float!) {
241-
users(where: { location_LTE: { point: { longitude: $longitude, latitude: $latitude }, distance: 5000 } }) {
242-
name
243-
location {
244-
longitude
245-
latitude
246-
}
247-
}
297+
type Actor {
298+
id: ID!
299+
name: String!
300+
movies: [Movie!]! @relationship(type: "ACTED_IN", direction: OUT)
248301
}
249302
----
250303

251-
Similarly, for a `CartesianPoint` type, all filters take the following type as an argument:
304+
The `_IN` operator is available on non-array fields, and accepts an array argument:
252305

253306
[source, graphql, indent=0]
254307
----
255-
input CartesianPointDistance {
256-
point: CartesianPoint!
257-
distance: Float!
308+
query {
309+
movies(where: { year_IN: [1999, 2000, 2001] }) {
310+
title
311+
year
312+
}
258313
}
259314
----
260315

261-
The same query for a `CartesianPoint`:
316+
The query returns all movies released in the years 1999, 2000 and 2001.
317+
318+
Conversely, the `_INCLUDES` operator is available on array fields, and accepts a single argument:
262319

263320
[source, graphql, indent=0]
264321
----
265-
query CloseByUsers($x: Float!, $y: Float!) {
266-
users(where: { location_LTE: { point: { x: $x, y: $y }, distance: 5000 } }) {
267-
name
268-
location {
269-
x
270-
y
271-
}
322+
query {
323+
movies(where: { genres_INCLUDES: "Action" }) {
324+
title
325+
genres
272326
}
273327
}
274328
----
275329

276-
== Querying an interface
330+
The query returns all movies which have "Action" as one of their genres.
331+
332+
`_IN` and `_INCLUDES` are available for all types except `Boolean`.
333+
334+
== Interface filtering
277335

278336
You can use the `typename_IN` filter to filter interfaces.
279337
Refer to xref:types/interfaces.adoc#type-definitions-interfaced-types-querying[Type definitions -> Type -> Interface] for more details and an example.
280338

281339
== Relationship filtering
282340

283-
Relationship filtering depends on the type of relationship that you have:
341+
Relationship filtering depends on the type of relationship:
284342

285-
* `n..1`: filtering done on equality or inequality of the related nodes by specifying a filter on `field`.
286-
* `n..m`: filtering is done on the list of related nodes and is based on the https://neo4j.com/docs/cypher-manual/current/functions/predicate/[list predicates] available in Cypher:
343+
* `n..1`: the filtering is done on equality or inequality of the related nodes by specifying a filter on `field`.
344+
* `n..m`: the filtering is done on the list of related nodes and is based on the https://neo4j.com/docs/cypher-manual/current/functions/predicate/[list predicates] available in Cypher:
287345
** `field_ALL` - https://neo4j.com/docs/cypher-manual/current/functions/predicate/#functions-all[all]
288346
** `field_NONE` - https://neo4j.com/docs/cypher-manual/current/functions/predicate/#functions-none[none]
289347
** `field_SOME` - https://neo4j.com/docs/cypher-manual/current/functions/predicate/#functions-any[any]
290348
** `field_SINGLE` - https://neo4j.com/docs/cypher-manual/current/functions/predicate/#functions-single[single]
291349

292-
As an example, take these type definitions:
350+
For example, take these type definitions:
293351

294352
[source, graphql, indent=0]
295353
----
@@ -306,10 +364,12 @@ type Post {
306364
likes: [User!]! @relationship(type: "LIKES", direction: IN)
307365
}
308366
----
367+
309368
=== `n..1` relationships
310369

311-
An `author` represents an `n..1` relationship on `Post`, where a given `Post` is authored by one, and only one, `author`.
312-
The available filters here will be `author`.
370+
In the type definitions example, an `author` represents an `n..1` relationship on `Post`, where a given `Post` is authored by one, and only one, `author`.
371+
The available filter is `author`.
372+
313373
For example:
314374

315375
.Find all posts by a desired author
@@ -334,8 +394,9 @@ query {
334394

335395
=== `n..m` relationships
336396

337-
In the previous example, `posts` represents a `n..m` relationship on `User`, where a given `User` can have any number of `posts`.
338-
Here are some query examples:
397+
In the type definitions example, `posts` represents an `n..m` relationship on `User`, where a given `User` can have any number of `posts`.
398+
399+
For example:
339400

340401
.Find all users where all of their posts contain search term: `"neo4j"`
341402
[source, graphql, indent=0]
@@ -379,8 +440,8 @@ query {
379440

380441
== Aggregation filtering
381442

382-
This library offers, for each relationship, an aggregation key inside the `where` argument.
383-
It can be used both on the `node` and `edge` of a relationship.
443+
The Neo4j GraphQL library offers an aggregation key inside the `where` argument of each relationship.
444+
You can use it both on the `node` and `edge` of a relationship.
384445

385446
Here are some examples on how to apply this kind of filtering:
386447

@@ -464,7 +525,7 @@ query {
464525
}
465526
----
466527

467-
=== Operators
528+
=== With operators
468529

469530
Aggregation filtering can also be done with operators.
470531
They provide autogenerated filters available for each type on the `node` and `edge` of the specified relationship.

0 commit comments

Comments
 (0)