Filtering
When querying for data, a number of operators are available for different types in the where
argument of a query or mutation.
Equality operators
All types can be tested for either equality (_eq
) or non-equality (_ne
).
For example:
query {
users(where: {name: { _eq: "John" }})
id
name
}
For the |
Numerical operators
-
_LT
-
_LTE
-
_GT
-
_GTE
Here is an example of how to use them:
query {
users(where: {age: { _lt: 50 }}) {
id
name
age
}
}
Spatial types use numerical filtering differently and they also have additional options. See Spatial types filtering for more information.
These same operators are disabled by default in the case of String comparisons. To enable, explicitly add them in the features options:
const { Neo4jGraphQL } = require("@neo4j/graphql");
const neo4j = require("neo4j-driver");
const typeDefs = `
type User {
name: String
}
`;
const driver = neo4j.driver(
"bolt://localhost:7687",
neo4j.auth.basic("neo4j", "password")
);
const features = {
filters: {
String: {
LT: true,
GT: true,
LTE: true,
GTE: true
}
}
};
const neoSchema = new Neo4jGraphQL({ features, typeDefs, driver });
String comparison
The following case-sensitive comparison operators are only available for use on String
and ID
types:
-
_STARTS_WITH
-
_ENDS_WITH
-
_CONTAINS
Here is an example of how to use them:
query {
users(where: { name_STARTS_WITH: "J" }) {
id
name
}
}
RegEx matching
The filter _MATCHES
is also available for comparison of String
and ID
types.
It accepts RegEx strings as an argument and returns any matches.
Note that RegEx matching filters are disabled by default. This is because, on an unprotected API, they could potentially be used to execute a ReDoS attack against the backing Neo4j database.
If you want to enable them, set the features configuration object for each:
const features = {
filters: {
String: {
MATCHES: true,
}
}
};
const neoSchema = new Neo4jGraphQL({ features, typeDefs, driver });
For ID
:
const features = {
filters: {
String: {
ID: true,
}
}
};
const neoSchema = new Neo4jGraphQL({ features, typeDefs, driver });
For both String
and ID
:
const features = {
filters: {
String: {
MATCHES: true,
},
ID: {
MATCHES: true,
}
}
};
const neoSchema = new Neo4jGraphQL({ features, typeDefs, driver });
Array comparison
The following operator is available on non-array fields, and accepts an array argument:
-
_IN
Conversely, the following operator is available on array fields, and accepts a single argument:
-
_INCLUDES
These operators are available for all types apart from Boolean
.
Combining operators
All operators can be combined using the AND
, OR
, and NOT
operators.
They can also be stand-alone operators, which means that they can be used as such and not be appended to field names.
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.
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:
query {
actors(where: {
AND: [
{
OR: [
{ name_CONTAINS: "Keanu" },
{ NOT: { name_ENDS_WITH: "Pantoliano" } }
]
},
{
movies_SOME: { title: "The Matrix" }
}
]}
) {
name
movies {
title
}
}
}
Relationship filtering
Relationship filtering depends on the type of relationship that you have:
-
n..1
: filtering done on equality or inequality of the related nodes by specifying a filter onfield
. -
n..m
: filtering is done on the list of related nodes and is based on the list predicates available in Cypher:
As an example, take these type definitions:
type User {
id: ID!
name: String
posts: [Post!]! @relationship(type: "HAS_POST", direction: OUT)
}
type Post {
id: ID!
content: String
author: User! @relationship(type: "HAS_POST", direction: IN)
likes: [User!]! @relationship(type: "LIKES", direction: IN)
}
In the case of n..1
relationships
An author
represents an n..1
relationship on Post
, where a given Post
is authored by one, and only one, author
.
The available filters here will be author
.
For example:
query {
posts(where: { author: { id: "7CF1D9D6-E527-4ACD-9C2A-207AE0F5CB8C" } }) {
content
}
}
NOT
by an undesired authorquery {
posts(where: { NOT: { author: { id: "7CF1D9D6-E527-4ACD-9C2A-207AE0F5CB8C" } } }) {
content
}
}
In the case of n..m
relationships
In the previous example, posts
represents a n..m
relationship on User
, where a given User
can have any number of posts
.
Here are some query examples:
"neo4j"
query {
users(where: { posts_ALL: { content_CONTAINS: "neo4j" } }) {
name
}
}
"cypher"
query {
users(where: { posts_NONE: { content_CONTAINS: "cypher" } }) {
name
}
}
"graphql"
query {
users(where: { posts_SOME: { content_CONTAINS: "graphql" } }) {
name
}
}
"graph"
query {
users(where: { posts_SINGLE: { content_CONTAINS: "graph" } }) {
name
}
}
Aggregation filtering
This library offers, for each relationship, an aggregation key inside the where
argument.
It can be used both on the node
and edge
of a relationship.
Here are some examples on how to apply this kind of filtering:
-
Find posts where the number of likes are greater than 5
Schema exampletype User { name: String } type Post { content: String likes: [User!]! @relationship(type: "LIKES", direction: IN) }
Queryquery { posts(where: { likesAggregate: { count_GT: 5 } }) { content } }
-
Find flights where the average age of passengers is greater than or equal to 18
Schema exampletype Passenger { name: String age: Int } type Flight { code: String passengers: [Passenger!]! @relationship(type: "FLYING_ON", direction: IN) }
Queryquery { flights(where: { passengersAggregate: { node: { age_AVERAGE_GTE: 18 } } }) { code } }
-
Find movies where the shortest actor screen time is less than 10 minutes
Schema exampletype Movie { title: String actors: [Person!]! @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn") } type Person { name: String } interface ActedIn @relationshipProperties { screenTime: Int }
Queryquery { movies(where: { actorsAggregate: { edge: { screenTime_MIN_LT: 10 } } }) { title } }
Operators
Aggregation filtering can also be done with operators.
They provide autogenerated filters available for each type on the node
and edge
of the specified relationship.
Field type | Description | Operators | Example |
---|---|---|---|
|
A special 'top level' key inside the |
|
|
|
These operators are calculated against the length of each string. |
|
|
|
Used in the case of |
|
|
|
Used in the case of |
|
Type definitions
Query
|
|
Description. |
|
Type definitions
Query
|
|
No aggregation filters are available for ID. |
- |
- |