Filters and projections
After learning how to write a basic Cypher® query using MATCH and RETURN, you can add filters and change the projection to only return some fields, as well as work with parameters.
This page shows you how to achieve the resulting query when using the movies data set:
MATCH(m:Movie)
WHERE (m.title = "The Matrix" AND m.released < 2000)
RETURN m.title, m.tagline, m.released
This query returns all movies with the title "The Matrix" released before the year of 2000.
It only returns the movie "The Matrix", released in 1999.
Filtering
Adding filters to a MATCH clause is similar to how you add the RETURN clause:
-
Use the method
.where:const movieNode = new Cypher.Node() const clause = new Cypher.Match(new Cypher.Pattern(movieNode, { labels: ["Movie"] })) .where() .return(movieNode); -
Then, to add a condition to the filter, for example:
m.title = "The Matrix"-
Use the function
Cypher®.eq()to add an equality operator (=) to the where statement:.where(Cypher.eq()) -
Cypher®.eq()takes two arguments to compare. For the first one, add the propertytitleofmovieNode:movieNode.property("title") -
The second argument is the value to compare (
"The Matrix"). Pass it as a parameter withnew Cypher®.Param:new Cypher.Param("The Matrix")Cypher®.Paramreplaces the string with a suitable$param, to avoid injecting values directly into the generated Cypher.
-
-
Your
MATCHclause should now look like this:const clause = new Cypher.Match(new (movieNode, { labels: ["Movie"] })) .where(Cypher.eq(movieNode.property("title"), new Cypher.Param("The Matrix"))) .return(movieNode); -
Run the script again (
node main.js). This results in the following Cypher®:MATCH (this0:Movie) WHERE this0.title = $param0 RETURN this0It filters
Movienodes by their title when they match a parameter, but the parameter itself is missing from the output. To fix that, modify the build process at the end of the script:const { cypher, params } = match.build(); console.log(cypher); console.log(params);Executing this script prompts the following Cypher® query and its parameters:
MATCH (this0:Movie) WHERE this0.title = $param0 RETURN this0{ param0: 'The Matrix' }
AND filtering
Here is how to add an AND filter to your query:
-
Use the method
.andafter.where, with a newCypher®.eqpredicate:.where(Cypher.eq(movieNode.property("title"), new Cypher.Param("The Matrix"))) .and(Cypher.lt(movieNode.property("released"), new Cypher.Param(2000)))This takes the same parameters as
.whereand ensures the proper concatenation of the filters withAND.In this case, the function
Cypher®.ltadds the operator<(less than). Like before, a property ofmovieNodeis compared to a parameter. -
Run the script again to get these results:
MATCH (this0:Movie) WHERE (this0.title = $param0 AND this0.released < $param1) RETURN this0{ param0: 'The Matrix', param1: 1999 }The
ANDoperation automatically adds parentheses to ensure operation precedence. This is an important feature when dealing with complex and nested filters. For more information see Advanced filtering.
Projection
Returning the full node is not necessary, but you can do that by explicitly setting a projection in RETURN.
For example:
RETURN m.title, m.tagline, m.released
To define these columns, you can pass the variables into the .return method:
.return(movieNode.property("title"), movieNode.property("tagline"), movieNode.property("year"));
The returned Cypher® has the explicit projection:
MATCH (this0:Movie)
WHERE (this0.title = $param0 AND this0.released < $param1)
RETURN this0.title, this0.tagline, this0.released
Reusing variables
The query so far filters and returns the properties id and title of the Movie nodes.
However, relying on the name of the properties might make maintenance unecessarily difficult.
To avoid that, make sure both filters and projections use the same property variable (in this case, movieNode.):
const titleProp = movieNode.property("title");
const yearProp = movieNode.property("released");
const taglineProp = movieNode.property("tagline");
const clause = new Cypher.Match(movieNode)
.where(Cypher.eq(titleProp, new Cypher.Param("The Matrix")))
.and(Cypher.lt(yearProp, new Cypher.Param(2000)))
.return(titleProp, taglineProp, yearProp);
This should keep different parts of the query in sync and also make the clause itself shorter.
|
Parameters can also be assigned to a variable and be reused. This can be particularly useful when having multiple filters over the same parameter. See an example in Relationships and advanced filtering. |
Conclusion
Your script should look like this:
import Cypher from "@neo4j/cypher-builder";
const movieNode = new Cypher.Node({
labels: ["Movie"],
});
const titleProp = movieNode.property("title");
const yearProp = movieNode.property("released");
const taglineProp = movieNode.property("tagline");
const clause = new Cypher.Match(new Cypher.Pattern(movieNode, { labels: ["Movie"] }))
.where(Cypher.eq(titleProp, new Cypher.Param("The Matrix")))
.and(Cypher.lt(yearProp, new Cypher.Param(2000)))
.return(titleProp, taglineProp, yearProp);
const { cypher, params } = clause.build();
console.log(cypher);
console.log(params);
It results in the following query:
MATCH (this0:Movie)
WHERE (this0.title = $param0 AND this0.released < $param1)
RETURN this0.title, this0.tagline, this0.released
{ param0: 'The Matrix', param1: 2000 }
You can now add parameters to simple queries.
Refer to Relationships and advanced filtering to learn how to add relationships and more advanced filters to this query.