Filtering
Operators
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 or non-equality. For the Boolean
type, these are the only available comparison operators.
Numerical operators
The following comparison operators are available for numeric types (Int
, Float
, BigInt
), Temporal Types and Spatial Types:
-
_LT
-
_LTE
-
_GTE
-
_GT
Filtering of spatial types is different to filtering of numerical types and also offers an additional filter - see Spatial Types.
String comparison
The following case-sensitive comparison operators are only available for use on String
and ID
types:
-
_STARTS_WITH
-
_ENDS_WITH
-
_CONTAINS
The following operators are disabled by default:
-
_LT
-
_LTE
-
_GT
-
_GTE
They can be enabled by explicitly adding 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 });
RegEx matching
The filter _MATCHES
is also available for comparison of String
and ID
types, which accepts a RegEx string as an argument and returns any matches.
Note that RegEx matching filters are disabled by default.
To enable the inclusion of this filter, set the config option enableRegex
to true
.
The nature of RegEx matching means that on an unprotected API, this could potentially be used to execute a ReDoS attack (https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS) against the backing Neo4j database.
Array comparison
The following two comparison operators are available on non-array fields, and accept an array argument:
-
_IN
Conversely, the following operators are available on array fields, and accept a single argument: -
_INCLUDES
These four operators are available for all types apart from Boolean
.
Usage
Using the type definitions from Queries, below are some example of how filtering can be applied when querying for data.
At the root of a Query
By using the where
argument on the Query field in question, you can return a User with a particular ID:
query {
users(where: { id: "7CF1D9D6-E527-4ACD-9C2A-207AE0F5CB8C" }) {
name
}
}
Combining operators
All above-mentioned operators can be combined using the AND
/OR
/NOT
operators.
They 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.
As an example, the below query matches all actors by the name of either "Keanu" or not belonging to the "Pantoliano" family, that played in "The Matrix" movie.
query {
actors(where: {
AND: [
{
OR: [
{ name_CONTAINS: "Keanu" },
{ NOT: { name_ENDS_WITH: "Pantoliano" } }
]
},
{
movies_SOME: { title: "The Matrix" }
}
]}
) {
name
movies {
title
}
}
}
Relationship Filtering
For each relationship field, field
, a set of filters are available depending on whether the relationship is n..1
or n..m
. In the case of n..1
, filtering is done on equality or inequality of the related node by specifying a filter on field
, respectively. In the case of n..m
, filtering is done on the list of related nodes and is based on the List Predicates available in Cypher.
Relationship Filtering Usage Examples
For this section take as type definitions the following:
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)
}
n..1
Relationships
In the above, an author
represents a n..1
relationship on Post
where a given Post
is authored by one, and only one, author
. The available filters here will be author
.
n..m
Relationships
In the above, posts
represents a n..m
relationship on User
where a given User
can have any number of posts
.
Find all users where all of their posts contain search term: "neo4j"
query {
users(where: { posts_ALL: { content_CONTAINS: "neo4j" } }) {
name
}
}
Find all users where none of their posts contain search term: "cypher"
query {
users(where: { posts_NONE: { content_CONTAINS: "cypher" } }) {
name
}
}
Aggregation Filtering
This library offers, for each relationship, an aggregation key inside the where argument. You can use the aggregation key to satisfy questions such as:
-
Find the posts where the number of likes are greater than 5
-
Find flights where the average age of passengers is greater than or equal to 18
-
Find movies where the shortest actor screen time is less than 10 minutes
You can use this where aggregation on both the node
and edge
of a relationship.
Aggregation Filtering Usage Examples
Find the posts where the number of likes are greater than 5
Given the schema:
type User {
name: String
}
type Post {
content: String
likes: [User!]! @relationship(type: "LIKES", direction: IN)
}
Answering the question:
query {
posts(where: { likesAggregate: { count_GT: 5 } }) {
content
}
}
Find flights where the average age of passengers is greater than or equal to 18
Given the schema:
type Passenger {
name: String
age: Int
}
type Flight {
code: String
passengers: [Passenger!]! @relationship(type: "FLYING_ON", direction: IN)
}
Answering the question:
query {
flights(where: { passengersAggregate: { node: { age_AVERAGE_GTE: 18 } } }) {
code
}
}
Find movies where the shortest actor screen time is less than 10 minutes
Given the schema:
type Movie {
title: String
actors: [Person!]! @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn")
}
type Person {
name: String
}
interface ActedIn {
screenTime: Int
}
Answering the question:
query {
movies(where: { actorsAggregate: { edge: { screenTime_MIN_LT: 10 } } }) {
title
}
}
Aggregation Filtering Operators
Below you will learn more about the autogenerated filters available on the aggregate key and for each type on the node
and edge
of the specified relationship.
Count
This is a special 'top level' key inside the where aggregation and will be available for all relationships. This is used to count the amount of relationships the parent node is connected to. The operators count has are as follows:
-
count_EQUAL
-
count_GT
-
count_GTE
-
count_LT
-
count_LTE
String
Fields of type String
have the following operators:
-
_AVERAGE_LENGTH_EQUAL
-
_AVERAGE_LENGTH_GT
-
_AVERAGE_LENGTH_GTE
-
_AVERAGE_LENGTH_LT
-
_AVERAGE_LENGTH_LTE
-
_SHORTEST_LENGTH_EQUAL
-
_SHORTEST_LENGTH_GT
-
_SHORTEST_LENGTH_GTE
-
_SHORTEST_LENGTH_LT
-
_SHORTEST_LENGTH_LTE
-
_LONGEST_LENGTH_EQUAL
-
_LONGEST_LENGTH_GT
-
_LONGEST_LENGTH_GTE
-
_LONGEST_LENGTH_LT
-
_LONGEST_LENGTH_LTE
These operators are calculated against the length of each string.
Numerical Types
Numerical types include the following:
-
Int
-
Float
-
BigInt
The types in the list above have the following operators:
-
_AVERAGE_EQUAL
-
_AVERAGE_GT
-
_AVERAGE_GTE
-
_AVERAGE_LT
-
_AVERAGE_LTE
-
_SUM_EQUAL
-
_SUM_GT
-
_SUM_GTE
-
_SUM_LT
-
_SUM_LTE
-
_MIN_EQUAL
-
_MIN_GT
-
_MIN_GTE
-
_MIN_LT
-
_MIN_LTE
-
_MAX_EQUAL
-
_MAX_GT
-
_MAX_GTE
-
_MAX_LT
-
_MAX_LTE
Temporal Types
Temporal types include the following:
-
DateTime
-
LocalDateTime
-
LocalTime
-
Time
-
Duration
The types listed above have the following aggregation operators:
-
_MIN_EQUAL
-
_MIN_GT
-
_MIN_GTE
-
_MIN_LT
-
_MIN_LTE
-
_MAX_EQUAL
-
_MAX_GT
-
_MAX_GTE
-
_MAX_LT
-
_MAX_LTE
Whilst the Duration
type also has the following additional operators:
-
_AVERAGE_EQUAL
-
_AVERAGE_GT
-
_AVERAGE_GTE
-
_AVERAGE_LT
-
_AVERAGE_LTE
Was this page helpful?