# WHERE {bdg-primary-line}`GQL clause` Constrains a pattern or filters a projection: rows for which the condition is not true are dropped. ## Synopsis
WHERE condition

bold keywords · italic placeholders you supply · [ ] optional · ... repeatable. See Syntax conventions.

## Description `WHERE` is not a clause of its own. It attaches to one of three clauses and takes its meaning from the one it attaches to: - On [`MATCH`](match.md) it is part of the match. Every variable in the pattern is bound when the condition runs, and a match that fails it is not produced. - On [`OPTIONAL MATCH`](optional-match.md) it is part of the optional match. A row that fails the condition is **kept**, with the pattern's variables null. - On [`WITH`](with.md) it filters the projected rows, after any aggregation. This is where a condition over an aggregate goes. The condition must be a boolean expression. A value of another type is not coerced: a jsonb string or number in a condition raises an error rather than being treated as true. Aggregates are not allowed in a `WHERE`. Put them in a `WITH` and filter the result. `WHERE` on its own is a syntax error, and a query cannot end with it. The standalone, chainable filter is [`FILTER`](filter.md), which takes both `FILTER condition` and `FILTER WHERE condition`. ## Parameters condition : An expression of type boolean. Combine tests with `AND`, `OR`, `XOR` and `NOT`. ## Examples Every example runs against [the example dataset](../../get_started/example-dataset.md). ### Compare a property ```cypher MATCH (m:movie) WHERE m.year > 2015 RETURN m.title AS film, m.year AS year ORDER BY year, film; ``` ``` film | year ----------------------------+------ "Blade Runner 2049" | 2017 "The Matrix Resurrections" | 2021 (2 rows) ``` ### Combine conditions ```cypher MATCH (m:movie) WHERE m.genre = 'Action' AND m.year < 1995 RETURN m.title AS film ORDER BY film; ``` ``` film ------------------------------ "Terminator 2: Judgment Day" "The Terminator" (2 rows) ``` `XOR` is available alongside `AND`, `OR` and `NOT`: ```cypher MATCH (m:movie) WHERE m.genre = 'Action' XOR m.year < 1995 RETURN count(*) AS n; ``` ``` n --- 8 (1 row) ``` ### Test a label `label()` returns an element's label as a string, for vertices and edges alike: ```cypher MATCH (n) WHERE label(n) = 'person' RETURN count(*) AS n; ``` ``` n ---- 28 (1 row) ``` `IN` over a list of names is how a pattern matches several edge labels, which an edge pattern cannot express: ```cypher MATCH (p:person)-[r]->(m:movie) WHERE label(r) IN ['acted_in', 'directed'] RETURN count(r) AS edges; ``` ``` edges ------- 46 (1 row) ``` ### Match on a substring or a pattern `STARTS WITH`, `ENDS WITH` and `CONTAINS` test a string property: ```cypher MATCH (m:movie) WHERE m.title STARTS WITH 'The Matrix' RETURN count(*) AS n; ``` ``` n --- 4 (1 row) ``` ```cypher MATCH (m:movie) WHERE m.title ENDS WITH 'Runner' RETURN m.title AS film; ``` ``` film ---------------- "Blade Runner" (1 row) ``` `=~` matches a POSIX regular expression: ```cypher MATCH (m:movie) WHERE m.title =~ '^Blade.*' RETURN m.title AS film ORDER BY film; ``` ``` film --------------------- "Blade Runner" "Blade Runner 2049" (2 rows) ``` Negate with `NOT`; there is no `!~` for a property and no `NOT LIKE`: ```cypher MATCH (m:movie) WHERE NOT m.title STARTS WITH 'The' RETURN count(*) AS n; ``` ``` n ---- 11 (1 row) ``` ### Test for a missing property A property that was never set reads as null, so `IS NULL` is the test for its absence: ```cypher MATCH (m:movie) WHERE m.runtime IS NULL RETURN count(*) AS n; ``` ``` n ---- 18 (1 row) ``` ### Test for a pattern A subquery expression tests whether a pattern exists without binding anything from it: ```cypher MATCH (p:person) WHERE EXISTS { MATCH (p)-[:directed]->() } RETURN p.name AS director ORDER BY director LIMIT 4; ``` ``` director --------------------- "Andrew Niccol" "Christopher Nolan" "Denis Villeneuve" "James Cameron" (4 rows) ``` ### Filter an aggregate with WITH An aggregate in a `WHERE` is refused: ```cypher MATCH (p:person)-[:acted_in]->(m:movie) WHERE count(m) > 1 RETURN p.name; ``` ``` ERROR: aggregate functions are not allowed in WHERE ``` Aggregate in a `WITH`, then filter the result. The `WITH` clause's own `WHERE` runs after the grouping: ```cypher MATCH (p:person)-[:acted_in]->(m:movie) WITH p, count(m) AS films WHERE films >= 3 RETURN p.name AS actor, films ORDER BY actor; ``` ``` actor | films -------------------------+------- "Arnold Schwarzenegger" | 3 "Keanu Reeves" | 4 (2 rows) ``` ## Notes A property holds a jsonb value, and comparing it to a literal compares jsonb values. In jsonb ordering a number sorts above every string, so a quoted number compared against a numeric property is not the comparison you meant: ```cypher MATCH (m:movie {title: 'The Matrix'}) RETURN m.year > '9999' AS num_gt_str, m.year > 1990 AS num_gt_num; ``` ``` num_gt_str | num_gt_num ------------+------------ t | t (1 row) ``` Write the literal in the property's own type, or cast the property with `m.year::int > 1990`, when the stored type is not the one you expect. ```{note} `WHERE` takes a boolean and nothing else. `WHERE m.title` raises `cannot cast "The Matrix" (jsonb type string) to boolean`, where a language with truthiness would treat a non-empty string as true. Compare explicitly, or use `IS NOT NULL`. ``` ## Compatibility ### Labeled predicate (ISO/IEC 39075 §19.9) The standard writes a label test as `n IS LABELED movie`, with `n:movie` as a shorthand. AgensGraph accepts neither; use `label(n) = 'movie'`. ### Pattern predicates A bare pattern is not an expression, so it cannot be used as a predicate: `WHERE (m)-[:related_to]->(:movie)` is a syntax error, and so is the unlabelled `WHERE (m)-[]->()`. Wrap it in `EXISTS { MATCH ... }`, which the standard defines in §19.4 and AgensGraph supports. ### SQL string operators `LIKE` and `NOT LIKE` are not part of a Cypher condition. `WHERE m.title LIKE 'Blade%'` is a syntax error, with or without a cast. Use `STARTS WITH`, `ENDS WITH`, `CONTAINS` or `=~`. To use the SQL operators, wrap the Cypher in SQL; see [combining SQL and Cypher](../../querying/combining-sql-and-cypher.md). ## See also - [`MATCH`](match.md) — the clause `WHERE` most often attaches to - [`OPTIONAL MATCH`](optional-match.md) — where a failed condition keeps the row - [`WITH`](with.md) — filtering after a projection or an aggregate - [`FILTER`](filter.md) — the standalone filter clause - [Subquery expressions](subquery-expressions.md) — `EXISTS`, `COUNT`, `COLLECT` and the rest