-
Notifications
You must be signed in to change notification settings - Fork 63
Not a path pattern expression #1431
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
8b4efc1
bbcc228
9ccc313
e486abe
ffe5362
9609711
4319092
d4012a3
7f87ba9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,243 @@ | ||
| = Label expression predicates | ||
| :description: This page describes how to use label expression predicates with Cypher. | ||
|
|
||
| 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 | ||
|
|
||
| [source, syntax] | ||
| ---- | ||
| <expr>:<label-expression> | ||
| ---- | ||
|
|
||
| Where `<expr>` is any Cypher expression and `<label-expression>` is any Cypher xref::patterns/reference.adoc#label-expressions[label expression]. | ||
|
|
||
| [[example-graph]] | ||
| == Example graph | ||
|
|
||
| The following graph is used for the examples on this page: | ||
|
|
||
| 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 whether a node has a certain label | ||
|
|
||
| Given that `p` is a node, `p:Manager` tests whether `p` has the label `Manager` or not and results in `true` or `false`, respectively. | ||
|
|
||
| [source, cypher] | ||
| ---- | ||
| MATCH (p:Person) | ||
| RETURN p.name AS name, p:Manager AS isManager | ||
| ---- | ||
|
|
||
| [role="queryresult",options="header,footer",cols="2*<m"] | ||
| |=== | ||
| | name | isManager | ||
|
|
||
| | "Alice" | true | ||
| | "Cecil" | false | ||
| | "Cecilia" | false | ||
| | "Charlie" | false | ||
| | "Daniel" | false | ||
| | "Eskil" | false | ||
|
|
||
| 2+d|Rows: 6 | ||
| |=== | ||
|
|
||
| Given that `p` is a node and a more complex xref::patterns/reference.adoc#label-expressions[label expression], e.g, `Manager|Director|CEO`, `p:Manager|Director|CEO` tests whether node `p` matches the label expression `Manager|Director|CEO` or not and results in `true` or `false`, respectively. | ||
| More specifically, `p:Manager|Director|CEO` tests whether `p` has at least one of the three labels `Manager`, `Director`, and `CEO`. | ||
|
|
||
| [source, cypher] | ||
| ---- | ||
| MATCH (p:Person) | ||
| RETURN p.name AS name, | ||
| p:Manager|Director|CEO AS isManager | ||
| ---- | ||
|
|
||
| [role="queryresult",options="header,footer",cols="2*<m"] | ||
| |=== | ||
| | name | isManager | ||
|
|
||
| | "Alice" | true | ||
| | "Cecil" | false | ||
| | "Cecilia" | false | ||
| | "Charlie" | false | ||
| | "Daniel" | true | ||
| | "Eskil" | true | ||
|
|
||
| 2+d|Rows: 6 | ||
| |=== | ||
|
|
||
| `p:!CEO` tests whether `p` does not have the label `CEO`. | ||
|
|
||
| [source, cypher] | ||
| ---- | ||
| MATCH (p:Person)-[r]->(m) | ||
| RETURN p.name AS name, | ||
| m:!CEO AS doesNotWorkDirectlyForTheCEO | ||
| ---- | ||
|
|
||
| [role="queryresult",options="header,footer",cols="2*<m"] | ||
| |=== | ||
| | name | doesNotWorkDirectlyForTheCEO | ||
|
|
||
| | "Alice" | true | ||
| | "Cecil" | true | ||
| | "Cecilia" | true | ||
| | "Charlie" | true | ||
| | "Daniel" | false | ||
|
|
||
| 2+d|Rows: 5 | ||
| |=== | ||
|
|
||
| When `<exp>` 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] | ||
| ---- | ||
| 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"] | ||
| |=== | ||
| | name | doesNotWorkDirectlyForTheCEO | ||
|
|
||
| | "Alice" | true | ||
| | "Cecil" | true | ||
| | "Cecilia" | true | ||
| | "Charlie" | true | ||
| | "Daniel" | false | ||
| | "Eskil" | null | ||
|
|
||
| 2+d|Rows: 6 | ||
| |=== | ||
|
|
||
| The function xref:functions/scalar.adoc#functions-coalesce[coalesce] allows to turn `null` into a default value: | ||
|
|
||
| [source, cypher] | ||
| ---- | ||
| MATCH (p:Person) | ||
| OPTIONAL MATCH (p)-[r]->(m) | ||
| RETURN p.name AS name, | ||
| coalesce(m:!CEO, false) AS doesNotWorkDirectlyForTheCEO | ||
| ---- | ||
|
|
||
| [role="queryresult",options="header,footer",cols="2*<m"] | ||
| |=== | ||
| | name | doesNotWorkDirectlyForTheCEO | ||
|
|
||
| | "Alice" | true | ||
| | "Cecil" | true | ||
| | "Cecilia" | true | ||
| | "Charlie" | true | ||
| | "Daniel" | false | ||
| | "Eskil" | false | ||
|
|
||
| 2+d|Rows: 6 | ||
| |=== | ||
|
|
||
| [role=label--new-Neo4j-2025.07 label--cypher-25-only] | ||
| [[dynamic-node-label-expression-predicate]] | ||
| == Test whether a node matches a dynamic label expression | ||
|
|
||
| If you don't know the manager labels, you can infer a list of `managerLabels` by collecting all non-`Person` labels from people with a direct report. | ||
| You can test nodes with the label expression predicate to match a xref:patterns/reference.adoc#dynamic-label-and-type-expressions[dynamic label expression]. | ||
| `p:$any(managerLabels)` tests whether a node `p` has at least on of the label in the list `managerLabels`. | ||
|
|
||
| [source, cypher] | ||
| ---- | ||
| MATCH ()-[r]->(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 | ||
| ---- | ||
|
Comment on lines
+169
to
+177
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. again, no tags? (not sure how many we need for the cheat sheet 🤔 )
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So I remembered correctly that they are for the cheat sheet. The ones with tags are my picks. But please, just take them as uninformed suggestions. I have no higher understanding of what typically is expected to go into the cheat sheet. I am just running on very basic subjective assumptions. Feel free to adjust that. |
||
|
|
||
| [role="queryresult",options="header,footer",cols="2*<m"] | ||
| |=== | ||
| | name | isManager | ||
|
|
||
| | "Alice" | true | ||
| | "Cecil" | false | ||
| | "Cecilia" | false | ||
| | "Charlie" | false | ||
| | "Daniel" | true | ||
| | "Eskil" | true | ||
|
|
||
| 2+d|Rows: 6 | ||
| |=== | ||
|
|
||
| [node-label-expression-predicate] | ||
| == Test whether a relationship has a certain relationship type | ||
|
|
||
| Given that `r` is a relationship, `r:WORKS_FOR` tests whether `r` has the relationship type `WORKS_FOR` or not and result in `true` or `false`, respectively. | ||
|
|
||
| [source, cypher] | ||
| ---- | ||
| MATCH (p:Person)-[r]->() | ||
| RETURN p.name AS name, | ||
| r:WORKS_FOR AS isNotManager | ||
| ---- | ||
|
|
||
| [role="queryresult",options="header,footer",cols="2*<m"] | ||
| |=== | ||
| | name | isNotManager | ||
|
|
||
| | "Alice" | false | ||
| | "Cecil" | true | ||
| | "Cecilia" | true | ||
| | "Charlie" | true | ||
| | "Daniel" | false | ||
|
|
||
| 2+d|Rows: 5 | ||
| |=== | ||
|
|
||
| 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 `null` into a default value. | ||
|
|
||
| [source, cypher] | ||
| ---- | ||
| MATCH (p:Person) | ||
| OPTIONAL MATCH ()-[r]->(p) | ||
| RETURN DISTINCT | ||
| p.name AS name, | ||
| coalesce(r:WORKS_FOR|REPORTS_TO, false) AS hasReports | ||
| ---- | ||
|
|
||
| [role="queryresult",options="header,footer",cols="2*<m"] | ||
| |=== | ||
| | name | hasReports | ||
|
|
||
| | "Alice" | true | ||
| | "Cecil" | false | ||
| | "Cecilia" | false | ||
| | "Charlie" | false | ||
| | "Daniel" | true | ||
| | "Eskil" | true | ||
|
|
||
| 2+d|Rows: 6 | ||
| |=== | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -127,3 +127,59 @@ RETURN exists((:Person)-[:WORKS_FOR {since: 2023}]->(:Person {name: "Alice"})) A | |
|
|
||
| 1+d|Rows: 1 | ||
| |=== | ||
|
|
||
| [[not-patterns]] | ||
| == Expressions similar to path pattern expressions | ||
|
|
||
| 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. | ||
|
|
||
| .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 query result however is the same for both `p:Person` and `(p:Person)`: | ||
| [source, cypher] | ||
| ---- | ||
| MATCH (employee:Person)-[:WORKS_FOR]->(p) | ||
| WHERE p:Person | ||
| RETURN employee.name AS employee, p:Person AS workForAPerson | ||
| ---- | ||
|
|
||
| .Result | ||
| [role="queryresult",options="header,footer",cols="2*<m"] | ||
| |=== | ||
| | employee | workForAPerson | ||
|
|
||
| | "Cecil" | true | ||
| | "Cecilia" | true | ||
|
|
||
| 2+d|Rows: 2 | ||
| |=== | ||
|
|
||
| `(p)` 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)` is the variable `p` in parentheses. | ||
|
|
||
| `(p)` does result in the value of variable `p`. | ||
| If `p` is not a Boolean, then `(p)` does not result in a Boolean either. | ||
| Hence, the following query throws an error: | ||
|
|
||
| .Parenthesized node variable | ||
| [source, cypher, role=test-fail] | ||
| ---- | ||
| MATCH (employee:Person)-[:WORKS_FOR]->(p) | ||
| WHERE (p) | ||
| RETURN employee.name AS employee | ||
| ---- | ||
|
|
||
| [source, error] | ||
| ---- | ||
| Invalid input 'Node' for `p`. Expected to be Boolean. | ||
| ---- | ||
|
Comment on lines
+182
to
+185
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not necessary for this PR, but we should maybe think about starting to use the GQL errors in the Cypher manual instead.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You mean the showing the code? — because the message is what I get on 2025.10.1, i.e. it is the message that comes with the code. I guess that is a topic for the error team sync. It should have PM involvement, considering how error should be shown in docs (e.g. with position and carrot) and be done as a concerted change to the whole docs.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, showing the code and status description rather than or additional to the message. I will write it up for an upcoming error meeting, I agree it does not make much sense to do it for one random example but it should be consistently applied
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added it like this to next meeting:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Linking to the status code doc would be very reasonable. The docs colleagues maybe can even come up if a macro so that in the ascii doc sources you only have put the marco with the status code and it will generate a nice up-to-date presentation of the error incl. link to the respective status code doc page. |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no tags for this node-label-expression-predicate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I never the remember the purpose of the tags. I thought they mark which examples go into the cheat sheet, so I picked just some of them. But maybe the cheat sheet things was somethings else. If all need a tag, then so be it.