From 8b4efc10ec6d13339d519aec04c53276d1826a42 Mon Sep 17 00:00:00 2001 From: hvub Date: Wed, 26 Nov 2025 13:42:11 +0100 Subject: [PATCH 1/6] not a path pattern expression --- modules/ROOT/content-nav.adoc | 1 + .../label_expression_predicates_graph.svg | 280 ++++++++++++++++++ modules/ROOT/pages/expressions/index.adoc | 1 + .../pages/expressions/predicates/index.adoc | 1 + .../label-expression-predicates.adoc | 249 ++++++++++++++++ .../predicates/path-pattern-expressions.adoc | 56 ++++ 6 files changed, 588 insertions(+) create mode 100644 modules/ROOT/images/label_expression_predicates_graph.svg create mode 100644 modules/ROOT/pages/expressions/predicates/label-expression-predicates.adoc diff --git a/modules/ROOT/content-nav.adoc b/modules/ROOT/content-nav.adoc index e07c65db3..6cafffa9c 100644 --- a/modules/ROOT/content-nav.adoc +++ b/modules/ROOT/content-nav.adoc @@ -76,6 +76,7 @@ *** xref:expressions/predicates/comparison-operators.adoc[] *** xref:expressions/predicates/list-operators.adoc[] *** xref:expressions/predicates/string-operators.adoc[] +*** xref:expressions/predicates/label-expression-predicates.adoc[] *** xref:expressions/predicates/path-pattern-expressions.adoc[] *** xref:expressions/predicates/type-predicate-expressions.adoc[] ** xref:expressions/node-relationship-operators.adoc[] diff --git a/modules/ROOT/images/label_expression_predicates_graph.svg b/modules/ROOT/images/label_expression_predicates_graph.svg new file mode 100644 index 000000000..39d66658d --- /dev/null +++ b/modules/ROOT/images/label_expression_predicates_graph.svg @@ -0,0 +1,280 @@ + + + + + + + + + + + + + + + WORKS_FOR + + + + + + + + + + + + + + WORKS_FOR + + + + + + + + + + + + + + REPORTS_TO + + + + + + + + + + + + + + WORKS_FOR + + + + + + + + + + + + + + REPORTS_TO + + + + + + + + + + + + + + Person + Manager + + + + + + + + + + name: + 'Alice' + age: + 65 + skills: + ['Java', 'Python'] + + + + + + + + + + + + + + + + Person + Developer + + + + + + + + + + name: + 'Cecil' + age: + 25 + skills: + ['Java', 'Python'] + + + + + + + + + + + + + + + + Person + Developer + + + + + + + + + + name: + 'Cecilia' + age: + 31 + skills: + ['JavaScript', 'TypeScript'] + + + + + + + + + + + + + + + + Person + Engineer + + + + + + + + + + name: + 'Charlie' + age: + 61 + skills: + ['C++', 'Python'] + + + + + + + + + + + + + + + + Person + Director + + + + + + + + + + name: + 'Daniel' + age: + 39 + skills: + ['JavaScript', 'Slides'] + + + + + + + + + + + + + + + + Person + CEO + + + + + + + + + + name: + 'Eskil' + age: + 39 + skills: + ['Slides', 'ChatGPT'] + + + + + + + + \ No newline at end of file diff --git a/modules/ROOT/pages/expressions/index.adoc b/modules/ROOT/pages/expressions/index.adoc index 3e02f1d16..2deab8b38 100644 --- a/modules/ROOT/pages/expressions/index.adoc +++ b/modules/ROOT/pages/expressions/index.adoc @@ -10,6 +10,7 @@ For details and examples of specific expressions, see the following sections: ** xref:expressions/predicates/comparison-operators.adoc[]: `=`, `<>`, `<`, `>`, `\<=`, `>=`, `IS NULL`, `IS NOT NULL` ** xref:expressions/predicates/list-operators.adoc[]: `IN` ** xref:expressions/predicates/string-operators.adoc[]: `STARTS WITH`, `ENDS WITH`, `CONTAINS`, `IS NORMALIZED`, `IS NOT NORMALIZED`, `=~` +** xref:expressions/predicates/label-expression-predicates.adoc[]: information about how to test whether a node or relationship matches a label expression or not. ** xref:expressions/predicates/path-pattern-expressions.adoc[]: information about filtering queries with path pattern expressions. ** xref:expressions/predicates/type-predicate-expressions.adoc[]: information about how to verify the value type of a Cypher expression. * xref:expressions/node-relationship-operators.adoc[]: information about how to access `NODE` and `RELATIONSHIP` property values with `.` and `[]`. diff --git a/modules/ROOT/pages/expressions/predicates/index.adoc b/modules/ROOT/pages/expressions/predicates/index.adoc index ce68429c0..de890feb8 100644 --- a/modules/ROOT/pages/expressions/predicates/index.adoc +++ b/modules/ROOT/pages/expressions/predicates/index.adoc @@ -9,6 +9,7 @@ This chapter is divided into the following sections: * xref:expressions/predicates/comparison-operators.adoc[]: `=`, `<>`, `<`, `>`, `\<=`, `>=`, `IS NULL`, `IS NOT NULL` * xref:expressions/predicates/list-operators.adoc[]: `IN` * xref:expressions/predicates/string-operators.adoc[]: `STARTS WITH`, `ENDS WITH`, `CONTAINS`, `IS NORMALIZED`, `IS NOT NORMALIZED`, `=~` +* xref:expressions/predicates/label-expression-predicates.adoc[]: information about how to test whether a node or relationship matches a label expression or not. * xref:expressions/predicates/path-pattern-expressions.adoc[]: information about filtering queries with path pattern expressions. * xref:expressions/predicates/type-predicate-expressions.adoc[]: information about how to verify the value type of a Cypher expression. diff --git a/modules/ROOT/pages/expressions/predicates/label-expression-predicates.adoc b/modules/ROOT/pages/expressions/predicates/label-expression-predicates.adoc new file mode 100644 index 000000000..cdd71f243 --- /dev/null +++ b/modules/ROOT/pages/expressions/predicates/label-expression-predicates.adoc @@ -0,0 +1,249 @@ += Label expression predicates +:description: This page describes how to use label expression predicates with Cypher. + +A label expression predicate can be used to verify that the labels of a node or the relationship type of a relationship matches a given label expression. + +[[label-expression-predicat-syntax]] +== Syntax + +[source, syntax] +---- +: +---- + +Where `` is any Cypher expression and `` is any Cypher xref::patterns/reference.adoc#label-expressions[label expression]. + +[[example-graph]] +== Example graph + +The following graph is used for the examples below: + +image::label_expression_predicates_graph.svg[width="700",role="middle"] + +To recreate the graph, run the following query against an empty Neo4j database: + +[source, cypher] +---- +CREATE (alice:Person&Manager {name:'Alice', age: 65, skills: ['Java', 'Python']}), + (cecil:Person&Developer {name: 'Cecil', age: 25, skills: ['Java', 'Python']}), + (cecilia:Person&Developer {name: 'Cecilia', age: 31, skills: ['JavaScript', 'TypeScript']}), + (charlie:Person&Engineer {name: 'Charlie', age: 61, skills: ['C++', 'Python']}), + (daniel:Person&Director {name: 'Daniel', age: 39, skills: ['JavaScript', 'Slides']}), + (eskil:Person&CEO {name: 'Eskil', age: 39, skills: ['Slides', 'ChatGPT']}), + + (cecil)-[:WORKS_FOR]->(alice), + (cecilia)-[:WORKS_FOR]->(alice), + (charlie)-[:WORKS_FOR]->(daniel), + (alice)-[:REPORTS_TO]->(daniel), + (daniel)-[:REPORTS_TO]->(eskil) +---- + +[node-label-expression-predicate] +== Test that node has a certain labels + +Given `p` is a node, `p:Manager` tests whether node `p` has the label `Manager` or not and results in `true` or `false`, respectively. + +// tag::node-label-expression-predicate-1[] +[source, cypher] +---- +MATCH (p:Person) +RETURN p.name AS name, p:Manager AS isManager +---- +// end::node-label-expression-predicate-1[] + +[role="queryresult",options="header,footer",cols="2*(m) +RETURN p.name AS name, + m:!CEO AS doesNotWorkDirectlyForTheCEO +---- + +[role="queryresult",options="header,footer",cols="2*', then the label expression predicate results in `null`, e.g. if `p` is `null`, then `p:!CEO` results in `null`. + +[source, cypher] +---- +MATCH (p:Person) +OPTIONAL MATCH (p)-[r]->(m) +RETURN p.name AS name, + m:!CEO AS doesNotWorkDirectlyForTheCEO +---- + +[role="queryresult",options="header,footer",cols="2*(m) +RETURN p.name AS name, + coalesce(m:!CEO, false) AS doesNotWorkDirectlyForTheCEO +---- + +[role="queryresult",options="header,footer",cols="2*(p:Person) +UNWIND labels(p) AS label +FILTER label <> "Person" +RETURN COLLECT(label) AS managerLabels +NEXT +MATCH (p) +RETURN p.name AS name, p:$any(managerLabels) AS isManager +---- + +[role="queryresult",options="header,footer",cols="2*() +RETURN p.name AS name, + r:WORKS_FOR AS isNotManager +---- +// end::relationship-label-expression-predicate[] + +[role="queryresult",options="header,footer",cols="2*(p) +RETURN DISTINCT + p.name AS name, + coalesce(r:WORKS_FOR|REPORTS_TO, false) AS hasReports +---- + +[role="queryresult",options="header,footer",cols="2*(:Person {name: "Alice"})) A 1+d|Rows: 1 |=== + +[[not-patterns]] +== Not a path pattern expression + +Since any expression can be surrounded by parentheses, some expression when parenthesized may be confused for being a path pattern expression. +The following lists two examples of parenthesized expression that are not path pattern expression and explains what they are instead. + +`(p:Person)` is not a path pattern expression since it does not have at least one xref::patterns/reference.adoc#relationship-patterns[relationship] or xref::patterns/reference.adoc#variable-length-relationships[variable-length relationship]. +Instead, `(p:Person)` is the xref:expressions/predicates/label-expression-predicates.adoc[label expression predicate] `p:Person` in parentheses. + +.Parenthesized label expression predicate +[source, cypher] +---- +MATCH (employee:Person)-[:WORKS_FOR]->(p) + WHERE (p:Person) +RETURN employee.name AS employee, (p:Person) AS workForAPeron +---- + +The above query has the same result as teh query that used `p:Person` in stead of `(p:Person)`: +[source, cypher] +---- +MATCH (employee:Person)-[:WORKS_FOR]->(p) + WHERE p:Person +RETURN employee.name AS employee, p:Person AS workForAPeron +---- + +.Result +[role="queryresult",options="header,footer",cols="2*(p) + WHERE (p) +RETURN employee.name AS employee +---- + +[source, error] +---- +Invalid input 'Node' for `p`. Expected to be Boolean. +---- \ No newline at end of file From bbcc2286dfc4c1fc048cf6f63198c20498f6259a Mon Sep 17 00:00:00 2001 From: Hannes Voigt <30618026+hvub@users.noreply.github.com> Date: Sun, 30 Nov 2025 10:38:01 +0100 Subject: [PATCH 2/6] Apply suggestions from code review Co-authored-by: Louise Berglund --- .../expressions/predicates/path-pattern-expressions.adoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/ROOT/pages/expressions/predicates/path-pattern-expressions.adoc b/modules/ROOT/pages/expressions/predicates/path-pattern-expressions.adoc index 8eef2ee19..939d9196a 100644 --- a/modules/ROOT/pages/expressions/predicates/path-pattern-expressions.adoc +++ b/modules/ROOT/pages/expressions/predicates/path-pattern-expressions.adoc @@ -145,18 +145,18 @@ MATCH (employee:Person)-[:WORKS_FOR]->(p) RETURN employee.name AS employee, (p:Person) AS workForAPeron ---- -The above query has the same result as teh query that used `p:Person` in stead of `(p:Person)`: +The above query has the same result as the query that used `p:Person` instead of `(p:Person)`: [source, cypher] ---- MATCH (employee:Person)-[:WORKS_FOR]->(p) WHERE p:Person -RETURN employee.name AS employee, p:Person AS workForAPeron +RETURN employee.name AS employee, p:Person AS workForAPerson ---- .Result [role="queryresult",options="header,footer",cols="2* Date: Sun, 30 Nov 2025 10:40:00 +0100 Subject: [PATCH 3/6] review changes --- .../expressions/predicates/label-expression-predicates.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ROOT/pages/expressions/predicates/label-expression-predicates.adoc b/modules/ROOT/pages/expressions/predicates/label-expression-predicates.adoc index cdd71f243..30f7506d3 100644 --- a/modules/ROOT/pages/expressions/predicates/label-expression-predicates.adoc +++ b/modules/ROOT/pages/expressions/predicates/label-expression-predicates.adoc @@ -113,7 +113,7 @@ RETURN p.name AS name, 2+d|Rows: 5 |=== -When '', then the label expression predicate results in `null`, e.g. if `p` is `null`, then `p:!CEO` results in `null`. +When `` results in ´null`, then the label expression predicate results in `null`, e.g. if `p` is `null`, then `p:!CEO` results in `null`. [source, cypher] ---- @@ -171,7 +171,6 @@ Nodes can be tested with the label expression predicate to match xref:patterns/r [source, cypher] ---- -CYPHER 25 MATCH ()-[r]->(p:Person) UNWIND labels(p) AS label FILTER label <> "Person" @@ -223,6 +222,7 @@ RETURN p.name AS name, |=== If `r` is `null`, then the label expression predicate, e.g. `r:WORKS_FOR|REPORTS_TO` results in `null`. +The function xref:functions/scalar.adoc#functions-coalesce[coalesce] allows to turn a `null` into a default values. [source, cypher] ---- From e486abe158a6aac9d92d26513f106c5518476300 Mon Sep 17 00:00:00 2001 From: Hannes Voigt <30618026+hvub@users.noreply.github.com> Date: Thu, 4 Dec 2025 09:04:22 +0100 Subject: [PATCH 4/6] Apply suggestions from code review Co-authored-by: Richard Sill <156673635+rsill-neo4j@users.noreply.github.com> --- .../label-expression-predicates.adoc | 36 +++++++++---------- .../predicates/path-pattern-expressions.adoc | 8 ++--- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/modules/ROOT/pages/expressions/predicates/label-expression-predicates.adoc b/modules/ROOT/pages/expressions/predicates/label-expression-predicates.adoc index 30f7506d3..acc0fd479 100644 --- a/modules/ROOT/pages/expressions/predicates/label-expression-predicates.adoc +++ b/modules/ROOT/pages/expressions/predicates/label-expression-predicates.adoc @@ -1,7 +1,7 @@ = Label expression predicates :description: This page describes how to use label expression predicates with Cypher. -A label expression predicate can be used to verify that the labels of a node or the relationship type of a relationship matches a given label expression. +You can use a label expression predicate to verify that the labels of a node or the relationship type of a relationship match a given label expression. [[label-expression-predicat-syntax]] == Syntax @@ -16,7 +16,7 @@ Where `` is any Cypher expression and `` is any Cypher x [[example-graph]] == Example graph -The following graph is used for the examples below: +The following graph is used for the examples on this page: image::label_expression_predicates_graph.svg[width="700",role="middle"] @@ -39,17 +39,17 @@ CREATE (alice:Person&Manager {name:'Alice', age: 65, skills: ['Java', 'Python']} ---- [node-label-expression-predicate] -== Test that node has a certain labels +== Test whether a node has a certain label -Given `p` is a node, `p:Manager` tests whether node `p` has the label `Manager` or not and results in `true` or `false`, respectively. +Given that `p` is a node, `p:Manager` tests whether `p` has the label `Manager` or not and results in `true` or `false`, respectively. -// tag::node-label-expression-predicate-1[] +// tag::node-label-expression-predicate-simple[] [source, cypher] ---- MATCH (p:Person) RETURN p.name AS name, p:Manager AS isManager ---- -// end::node-label-expression-predicate-1[] +// end::node-label-expression-predicate-simple[] [role="queryresult",options="header,footer",cols="2*(:Person {name: "Alice"})) A |=== [[not-patterns]] -== Not a path pattern expression +== Expressions similar to path pattern expressions -Since any expression can be surrounded by parentheses, some expression when parenthesized may be confused for being a path pattern expression. -The following lists two examples of parenthesized expression that are not path pattern expression and explains what they are instead. +Since any expression can be wrapped in parentheses, some are very similar to path pattern expressions. +For example: `(p:Person)` is not a path pattern expression since it does not have at least one xref::patterns/reference.adoc#relationship-patterns[relationship] or xref::patterns/reference.adoc#variable-length-relationships[variable-length relationship]. Instead, `(p:Person)` is the xref:expressions/predicates/label-expression-predicates.adoc[label expression predicate] `p:Person` in parentheses. @@ -145,7 +145,7 @@ MATCH (employee:Person)-[:WORKS_FOR]->(p) RETURN employee.name AS employee, (p:Person) AS workForAPeron ---- -The above query has the same result as the query that used `p:Person` instead of `(p:Person)`: +The query result however is the same for both `p:Person` and `(p:Person)`: [source, cypher] ---- MATCH (employee:Person)-[:WORKS_FOR]->(p) From 96097111b858c70dd968305444a772e88f93dd1a Mon Sep 17 00:00:00 2001 From: Richard Sill Date: Thu, 4 Dec 2025 09:59:43 +0100 Subject: [PATCH 5/6] updated image --- .../label_expression_predicates_graph.svg | 310 ++---------------- 1 file changed, 30 insertions(+), 280 deletions(-) diff --git a/modules/ROOT/images/label_expression_predicates_graph.svg b/modules/ROOT/images/label_expression_predicates_graph.svg index 39d66658d..8abece4ef 100644 --- a/modules/ROOT/images/label_expression_predicates_graph.svg +++ b/modules/ROOT/images/label_expression_predicates_graph.svg @@ -1,280 +1,30 @@ - - - - - - - - - - - - - - - WORKS_FOR - - - - - - - - - - - - - - WORKS_FOR - - - - - - - - - - - - - - REPORTS_TO - - - - - - - - - - - - - - WORKS_FOR - - - - - - - - - - - - - - REPORTS_TO - - - - - - - - - - - - - - Person - Manager - - - - - - - - - - name: - 'Alice' - age: - 65 - skills: - ['Java', 'Python'] - - - - - - - - - - - - - - - - Person - Developer - - - - - - - - - - name: - 'Cecil' - age: - 25 - skills: - ['Java', 'Python'] - - - - - - - - - - - - - - - - Person - Developer - - - - - - - - - - name: - 'Cecilia' - age: - 31 - skills: - ['JavaScript', 'TypeScript'] - - - - - - - - - - - - - - - - Person - Engineer - - - - - - - - - - name: - 'Charlie' - age: - 61 - skills: - ['C++', 'Python'] - - - - - - - - - - - - - - - - Person - Director - - - - - - - - - - name: - 'Daniel' - age: - 39 - skills: - ['JavaScript', 'Slides'] - - - - - - - - - - - - - - - - Person - CEO - - - - - - - - - - name: - 'Eskil' - age: - 39 - skills: - ['Slides', 'ChatGPT'] - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From d4012a3b7fef570d73aabe9fb04bfded40f2674e Mon Sep 17 00:00:00 2001 From: Richard Sill Date: Mon, 8 Dec 2025 13:33:23 +0100 Subject: [PATCH 6/6] removed cheat sheet tags --- .../expressions/predicates/label-expression-predicates.adoc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/modules/ROOT/pages/expressions/predicates/label-expression-predicates.adoc b/modules/ROOT/pages/expressions/predicates/label-expression-predicates.adoc index acc0fd479..121072293 100644 --- a/modules/ROOT/pages/expressions/predicates/label-expression-predicates.adoc +++ b/modules/ROOT/pages/expressions/predicates/label-expression-predicates.adoc @@ -43,13 +43,11 @@ CREATE (alice:Person&Manager {name:'Alice', age: 65, skills: ['Java', 'Python']} Given that `p` is a node, `p:Manager` tests whether `p` has the label `Manager` or not and results in `true` or `false`, respectively. -// tag::node-label-expression-predicate-simple[] [source, cypher] ---- MATCH (p:Person) RETURN p.name AS name, p:Manager AS isManager ---- -// end::node-label-expression-predicate-simple[] [role="queryresult",options="header,footer",cols="2*() RETURN p.name AS name, r:WORKS_FOR AS isNotManager ---- -// end::relationship-label-expression-predicate[] [role="queryresult",options="header,footer",cols="2*