From 26208b5a5468c06f060c61960547d0d94a149ecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Tue, 22 Oct 2024 09:18:38 +0200 Subject: [PATCH 1/9] more --- modules/ROOT/pages/clauses/match.adoc | 377 ++++++++++++-------------- 1 file changed, 169 insertions(+), 208 deletions(-) diff --git a/modules/ROOT/pages/clauses/match.adoc b/modules/ROOT/pages/clauses/match.adoc index a26f46c2b..c0790979b 100644 --- a/modules/ROOT/pages/clauses/match.adoc +++ b/modules/ROOT/pages/clauses/match.adoc @@ -1,32 +1,9 @@ :description: The `MATCH` clause is used to search for the pattern described in it. include::https://raw.githubusercontent.com/neo4j-graphacademy/courses/main/asciidoc/ads/data-analysis.adoc[] -[[query-match]] = MATCH -[[match-introduction]] -== Introduction - The `MATCH` clause allows you to specify the patterns Neo4j will search for in the database. -This is the primary way of getting data into the current set of bindings. -For more information about how `MATCH` is used to find patterns (including xref:patterns/variable-length-patterns.adoc#quantified-path-patterns[quantified path patterns], xref:patterns/variable-length-patterns.adoc#quantified-relationships[quantified relationships], and xref:patterns/shortest-paths.adoc[shortest paths]), see the section on xref::patterns/index.adoc[Patterns]. - -`MATCH` is often coupled to a `WHERE` part which adds restrictions, or predicates, to the `MATCH` patterns, making them more specific. -The predicates are part of the pattern description, and should not be considered a filter applied only after the matching is done. -_This means that `WHERE` should always be put together with the `MATCH` clause it belongs to._ - -`MATCH` can occur at the beginning of the query or later, possibly after a `WITH`. -If it is the first clause, nothing will have been bound yet, and Neo4j will design a search to find the results matching the clause and any associated predicates specified in any `WHERE` part. -This could involve a scan of the database, a search for nodes having a certain label, or a search of an index to find starting points for the pattern matching. -Nodes and relationships found by this search are available as _bound pattern elements,_ and can be used for pattern matching of paths. -They can also be used in any further `MATCH` clauses, where Neo4j will use the known elements, and from there find further unknown elements. - -Cypher is declarative, and so usually the query itself does not specify the algorithm to use to perform the search. -Neo4j will automatically work out the best approach to finding start nodes and matching patterns. -Predicates in `WHERE` parts can be evaluated before pattern matching, during pattern matching, or after finding matches. -However, there are cases where you can influence the decisions taken by the query compiler. -Read more about indexes in xref:indexes/search-performance-indexes/managing-indexes.adoc[], and more about specifying hints to force Neo4j to solve a query in a specific way in xref::indexes/search-performance-indexes/index-hints.adoc[Planner hints and the USING keyword]. - [[match-example-graph]] == Example graph @@ -39,42 +16,41 @@ To recreate the graph, run the following query against an empty Neo4j database: [source, cypher, role=test-setup] ---- -CREATE - (charlie:Person {name: 'Charlie Sheen'}), - (martin:Person {name: 'Martin Sheen'}), - (michael:Person {name: 'Michael Douglas'}), - (oliver:Person {name: 'Oliver Stone'}), - (rob:Person {name: 'Rob Reiner'}), - (wallStreet:Movie {title: 'Wall Street'}), - (charlie)-[:ACTED_IN {role: 'Bud Fox'}]->(wallStreet), - (martin)-[:ACTED_IN {role: 'Carl Fox'}]->(wallStreet), - (michael)-[:ACTED_IN {role: 'Gordon Gekko'}]->(wallStreet), - (oliver)-[:DIRECTED]->(wallStreet), - (thePresident:Movie {title: 'The American President'}), - (martin)-[:ACTED_IN {role: 'A.J. MacInerney'}]->(thePresident), - (michael)-[:ACTED_IN {role: 'President Andrew Shepherd'}]->(thePresident), - (rob)-[:DIRECTED]->(thePresident), - (martin)-[:FATHER_OF]->(charlie) +CREATE (charlie:Person {name: 'Charlie Sheen'}), + (martin:Person {name: 'Martin Sheen'}), + (michael:Person {name: 'Michael Douglas'}), + (oliver:Person {name: 'Oliver Stone'}), + (rob:Person {name: 'Rob Reiner'}), + (wallStreet:Movie {title: 'Wall Street'}), + (charlie)-[:ACTED_IN {role: 'Bud Fox'}]->(wallStreet), + (martin)-[:ACTED_IN {role: 'Carl Fox'}]->(wallStreet), + (michael)-[:ACTED_IN {role: 'Gordon Gekko'}]->(wallStreet), + (oliver)-[:DIRECTED]->(wallStreet), + (thePresident:Movie {title: 'The American President'}), + (martin)-[:ACTED_IN {role: 'A.J. MacInerney'}]->(thePresident), + (michael)-[:ACTED_IN {role: 'President Andrew Shepherd'}]->(thePresident), + (rob)-[:DIRECTED]->(thePresident), + (martin)-[:FATHER_OF]->(charlie) ---- +[[find-nodes]] +== Find nodes + +For more information about finding node patterns, see xref:patterns/fixed-length-patterns#node-patterns[Patterns -> Node patterns]. -[[basic-node-finding]] -== Basic node finding -[[get-all-nodes]] -=== Get all nodes +[[find-all-nodes]] +=== Find all nodes By specifying a pattern with a single node and no labels, all nodes in the graph will be returned. -.Query -[source, cypher, indent=0] +.Find all nodes in a graph +[source, cypher] ---- MATCH (n) RETURN n ---- -Returns all the nodes in the database. - .Result [role="queryresult",options="header,footer",cols="1* Label expressions]. + +[[find-relationships]] +== Find relationships + +Relationships will only be matched once inside a single pattern. +Read more about this behavior in the section on xref::patterns/reference.adoc#graph-patterns-rules-relationship-uniqueness[relationship uniqueness]. -[[relationship-basics]] -== Relationship basics +For more information about relationship patterns, see xref:patterns/fixed-length-patterns#relationship patterns[Patterns -> Relationship patterns]. -[[outgoing-relationships]] -=== Outgoing relationships +[[empty-relationship-patterns]] +=== Empty relationship patterns -When the direction of a relationship is of interest, it is shown by using `-->` or `<--`. -For example: +By applying `--`, a pattern will be matched for a relationship with any direction and without any filtering on relationship types or properties. +When matching a relationship pattern, a node pattern `()` must be applied at both ends. -.Query -[source, cypher, indent=0] +.Find connected nodes using an empty relationship pattern +---- +MATCH (director {name: 'Oliver Stone'})--(n) +RETURN n +---- + +.Result +[source, role="queryresult",options="header,footer",cols="1*` or `<--`. + +.Find all nodes connected to `Oliver Stone` by an outgoing relationship. +[source, cypher] ---- MATCH (:Person {name: 'Oliver Stone'})-->(movie) RETURN movie.title ---- -Returns any nodes connected by an outgoing relationship to the `Person` node with the `name` property set to `Oliver Stone`. - .Result -[role="queryresult",options="header,footer",cols="1*(movie) RETURN type(r) ---- -Returns the type of each outgoing relationship from `Oliver Stone`. - .Result -[role="queryresult",options="header,footer",cols="1*(movie)<-[:DIRECTED]-(director) +RETURN movie.title, director.name ---- -Returns the `ACTED_IN` roles for the movie `Wall Street`. - .Result -[role="queryresult",options="header,footer",cols="1*(martin) +MATCH (charlie:Person)-[:ACTED_IN]->(movie:Movie) +WHERE charlie.name = 'Charlie Sheen' +RETURN movie.title ---- -This leads to the following graph: - -image::graph_match_clause_backtick.svg[width="600", role="middle"] +.Result +[role="queryresult",options="header,footer",cols="1*() -RETURN type(r) +MATCH (martin:Person)-[:ACTED_IN]->(movie:Movie) +WHERE martin.name = 'Martin Sheen' AND NOT EXISTS { + MATCH (movie)<-[:DIRECTED]-(director:Person {name: 'Oliver Stone'}) +} +RETURN movie.title ---- .Result [role="queryresult",options="header,footer",cols="1*(movie)<-[:DIRECTED]-(director) -RETURN movie.title, director.name +MATCH path = ()-[:ACTED_IN]->(movie:Movie) +RETURN path ---- -Returns the movie in which `Charlie Sheen` acted and its director. +.Result +[role="queryresult",options="header,footer",cols="1*(:Movie {title: "Wall Street"}) +| (:Person {name: "Martin Sheen"})-[:ACTED_IN {role: "Carl Fox"}]->(:Movie {title: "Wall Street"}) +| (:Person {name: "Martin Sheen"})-[:ACTED_IN {role: "A.J. MacInerney"}]->(:Movie {title: "The American President"}) +| (:Person {name: "Michael Douglas"})-[:ACTED_IN {role: "Gordon Gekko"}]->(:Movie {title: "Wall Street"}) +| (:Person {name: "Michael Douglas"})-[:ACTED_IN {role: "President Andrew Shepherd"}]->(:Movie {title: "The American President"}) +| Rows: 5 +|=== + + +.Find paths matching a pattern including a `WHERE` predicate +[source, cypher] +---- +MATCH path = (:Person)-[:ACTED_IN]->(movie:Movie)<-[:DIRECTED]-(:Person) +WHERE movie.title = 'Wall Street' +RETURN path +---- .Result -[role="queryresult",options="header,footer",cols="2*(:Movie {title: "Wall Street"})<-[:DIRECTED]-(:Person {name: "Oliver Stone"}) +| (:Person {name: "Martin Sheen"})-[:ACTED_IN {role: "Carl Fox"}]->(:Movie {title: "Wall Street"})<-[:DIRECTED]-(:Person {name: "Oliver Stone"}) +| (:Person {name: "Michael Douglas"})-[:ACTED_IN {role: "Gordon Gekko"}]->(:Movie {title: "Wall Street"})<-[:DIRECTED]-(:Person {name: "Oliver Stone"}) +|Rows: 3 |=== + +For more information about how `MATCH` is used to find patterns (including xref:patterns/variable-length-patterns.adoc#quantified-path-patterns[quantified path patterns], xref:patterns/variable-length-patterns.adoc#quantified-relationships[quantified relationships], and xref:patterns/shortest-paths.adoc[shortest paths]), see the section on xref::patterns/index.adoc[Patterns]. + +== WITH and using multiple MATCH clauses + +MATCH (martin:Person {name: 'Martin Sheen'})-[:ACTED_IN]->(movie:Movie) +WITH movie // Pass the movie variable to the next part of the query +MATCH (director:Person)-[:DIRECTED]->(movie) +RETURN director.name AS Director, movie.title AS MovieTitle + + +== MATCH with parameters + +:param movieTitle => 'Wall Street'; + MATCH (movie:Movie {title: $movieTitle}) + From 5c4df4027642ecbf303d9953acdada6c9cbcc00b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Tue, 22 Oct 2024 09:21:49 +0200 Subject: [PATCH 2/9] =?UTF-8?q?fix=C3=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/ROOT/pages/clauses/match.adoc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/modules/ROOT/pages/clauses/match.adoc b/modules/ROOT/pages/clauses/match.adoc index c0790979b..2970af92c 100644 --- a/modules/ROOT/pages/clauses/match.adoc +++ b/modules/ROOT/pages/clauses/match.adoc @@ -358,7 +358,15 @@ RETURN path For more information about how `MATCH` is used to find patterns (including xref:patterns/variable-length-patterns.adoc#quantified-path-patterns[quantified path patterns], xref:patterns/variable-length-patterns.adoc#quantified-relationships[quantified relationships], and xref:patterns/shortest-paths.adoc[shortest paths]), see the section on xref::patterns/index.adoc[Patterns]. -== WITH and using multiple MATCH clauses +== Multiple MATCH clauses, the WITH clause, and clause composition + +In Cypher, the output of a clause creates a new state of the graph, and a new table of intermediate results which serves as the input of the next clause. +The first clause takes as input the state of the graph before the query and an empty table of intermediate results. +The output of the last clause is the result of the query. + + +In Cypher, each clause has as input the state of the graph and a table of intermediate results +Each clause has as input the state of the graph and a table of intermediate results consisting of the current variables. The output of a clause is a new state of the graph and a new table of intermediate results, serving as input to the next clause. The first clause takes as input the state of the graph before the query and an empty table of intermediate results. The output of the last clause is the result of the query. MATCH (martin:Person {name: 'Martin Sheen'})-[:ACTED_IN]->(movie:Movie) WITH movie // Pass the movie variable to the next part of the query From 2991f8e40ceef62714e9571fa1d199872ae7172d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Thu, 24 Oct 2024 15:43:10 +0200 Subject: [PATCH 3/9] more updates --- modules/ROOT/pages/clauses/match.adoc | 195 ++++++++++++++++++++------ 1 file changed, 152 insertions(+), 43 deletions(-) diff --git a/modules/ROOT/pages/clauses/match.adoc b/modules/ROOT/pages/clauses/match.adoc index 2970af92c..0f89fca36 100644 --- a/modules/ROOT/pages/clauses/match.adoc +++ b/modules/ROOT/pages/clauses/match.adoc @@ -3,7 +3,8 @@ include::https://raw.githubusercontent.com/neo4j-graphacademy/courses/main/ascii = MATCH -The `MATCH` clause allows you to specify the patterns Neo4j will search for in the database. +The `MATCH` clause enables you to define specific patterns that the database will search for within its graph structure. +The `MATCH` clause can specify the nodes, relationships, and properties in a pattern, allowing for queries that traverse the graph to retrieve relevant data. [[match-example-graph]] == Example graph @@ -36,9 +37,9 @@ CREATE (charlie:Person {name: 'Charlie Sheen'}), [[find-nodes]] == Find nodes +The `MATCH` clause allows you to specify node patterns of varying complexity to retrieve from a graph. For more information about finding node patterns, see xref:patterns/fixed-length-patterns#node-patterns[Patterns -> Node patterns]. - [[find-all-nodes]] === Find all nodes @@ -110,32 +111,52 @@ RETURN n.name AS name, n.title AS title 2+|Rows: 7 |=== +.Node pattern using the `AND` (`&`) and negation (`!`) label expression +[source, cypher] +---- +MATCH (n:!Director&!Movie) +RETURN labels(n) AS label, count(n) AS labelCount +---- + +[NOTE] +The above query uses the xref:functions/list.adoc#functions-labels[`labels()`] and xref:functions/aggregating.adoc#functions-count[`count()`] functions. + +.Result +[role="queryresult",options="header,footer",cols="2* Label expressions]. [[find-relationships]] == Find relationships +The `MATCH` clause allows you to specify relationship patterns of varying complexity to retrieve from a graph. +Unlike a node pattern, a relationship pattern cannot be used in a `MATCH` clause without node patterns at both ends. +For more information about relationship patterns, see xref:patterns/fixed-length-patterns#relationship patterns[Patterns -> Relationship patterns]. + +[NOTE] Relationships will only be matched once inside a single pattern. Read more about this behavior in the section on xref::patterns/reference.adoc#graph-patterns-rules-relationship-uniqueness[relationship uniqueness]. -For more information about relationship patterns, see xref:patterns/fixed-length-patterns#relationship patterns[Patterns -> Relationship patterns]. - [[empty-relationship-patterns]] === Empty relationship patterns By applying `--`, a pattern will be matched for a relationship with any direction and without any filtering on relationship types or properties. -When matching a relationship pattern, a node pattern `()` must be applied at both ends. .Find connected nodes using an empty relationship pattern ---- MATCH (director {name: 'Oliver Stone'})--(n) -RETURN n +RETURN n AS connectedNodes ---- .Result [source, role="queryresult",options="header,footer",cols="1*` or `< [source, cypher] ---- MATCH (:Person {name: 'Oliver Stone'})-->(movie) -RETURN movie.title +RETURN movie.title AS movieTitle ---- .Result [source, role="queryresult",options="header,footer",cols="1*(movie) -RETURN type(r) +RETURN type(r) AS relType ---- +[NOTE] +The above query uses the xref:functions/scalar.adoc#functions-type[`type()` function]. + .Result [source, role="queryresult",options="header,footer",cols="1*()` will never match a relationship. + +[[multiple-relationships]] === Find multiple relationships A graph pattern can contain several relationship patterns. @@ -259,36 +285,36 @@ A graph pattern can contain several relationship patterns. [source, cypher] ---- MATCH (charlie {name: 'Charlie Sheen'})-[:ACTED_IN]->(movie)<-[:DIRECTED]-(director) -RETURN movie.title, director.name +RETURN movie.title AS movieTitle, director.name AS director ---- .Result [role="queryresult",options="header,footer",cols="2*(movie:Movie) WHERE charlie.name = 'Charlie Sheen' -RETURN movie.title +RETURN movie.title AS movieTitle ---- .Result [role="queryresult",options="header,footer",cols="1*(movie:Movie) WHERE martin.name = 'Martin Sheen' AND NOT EXISTS { MATCH (movie)<-[:DIRECTED]-(director:Person {name: 'Oliver Stone'}) } -RETURN movie.title +RETURN movie.title AS movieTitle ---- +[NOTE] +The above query uses an xref:subqueries/existential.adoc[`EXISTS` subquery]. + .Result [role="queryresult",options="header,footer",cols="1* Parameters]. + [[find-paths]] == Find paths -The `MATCH` clause can also be used to bind paths to variables. +The `MATCH` clause can also be used to bind whole paths to variables. .Find all paths matching a pattern [source, cypher] @@ -356,26 +423,68 @@ RETURN path |Rows: 3 |=== -For more information about how `MATCH` is used to find patterns (including xref:patterns/variable-length-patterns.adoc#quantified-path-patterns[quantified path patterns], xref:patterns/variable-length-patterns.adoc#quantified-relationships[quantified relationships], and xref:patterns/shortest-paths.adoc[shortest paths]), see the section on xref::patterns/index.adoc[Patterns]. +For more information about how `MATCH` is used to find patterns of varying complexity (including xref:patterns/variable-length-patterns.adoc#quantified-path-patterns[quantified path patterns], xref:patterns/variable-length-patterns.adoc#quantified-relationships[quantified relationships], and the xref:patterns/shortest-paths.adoc[shortest paths] between nodes), see the section on xref::patterns/index.adoc[Patterns]. == Multiple MATCH clauses, the WITH clause, and clause composition -In Cypher, the output of a clause creates a new state of the graph, and a new table of intermediate results which serves as the input of the next clause. -The first clause takes as input the state of the graph before the query and an empty table of intermediate results. -The output of the last clause is the result of the query. +In Cypher, a query’s behavior is defined by its clauses. +Each clause takes the current graph state and a table of intermediate results, processes them, and passes the updated graph state and results to the next clause. +The first clause starts with the graph's initial state and an empty table, while the final clause produces the query's result. +.Chaining consecutive `MATCH` clauses +[source, cypher] +---- +MATCH (:Person {name: 'Martin Sheen'})-[:ACTED_IN]->(movie:Movie) // <1> +MATCH (director:Person)-[:DIRECTED]->(movie) // <2> +RETURN director.name AS director, movie.title AS movieTitle +---- +<1> The result of the first `MATCH` clause is the variable `movie` which holds all the `Movies` that `Martin Sheen` has `ACTED_IN`. +<2> The second `MATCH` clause uses the `movie` variable to find any `Person` node with a `DIRECTED` relationship to those `Movie` nodes that `Martin Sheen` has `ACTED_IN`. -In Cypher, each clause has as input the state of the graph and a table of intermediate results -Each clause has as input the state of the graph and a table of intermediate results consisting of the current variables. The output of a clause is a new state of the graph and a new table of intermediate results, serving as input to the next clause. The first clause takes as input the state of the graph before the query and an empty table of intermediate results. The output of the last clause is the result of the query. +.Result +[role="queryresult",options="header,footer",cols="2*(movie:Movie) -WITH movie // Pass the movie variable to the next part of the query -MATCH (director:Person)-[:DIRECTED]->(movie) -RETURN director.name AS Director, movie.title AS MovieTitle +2+d| Rows: 2 +|=== +A variable can be implicitly carried over to the following clause by being referenced in another operation. +A variable can also be explicitly passed to the following clause using the `WITH` clause. +If a variable is neither implicitly nor explicitly carried over, it will be discarded and unavailable for reference later in the query. -== MATCH with parameters +.Using `WITH` and multiple `MATCH` clauses +[source, cypher] +---- +MATCH (actors:Person)-[:ACTED_IN]->(movies:Movie) // <1> +WITH actors, count(movies) AS movieCount // <2> +ORDER BY movieCount DESC +LIMIT 1 // <3> +MATCH (actors)-[:ACTED_IN]->(movies) // <4> +RETURN actors.name AS actor, movieCount, collect(movies.title) AS movies +---- +<1> The `Person` and `Movie` nodes matched in this step are stored in variables. +which are then passed on to the second row of the query. +<2> The `movie` variable is here implicitly imported by its occurrence in the `count()` function. +The `WITH` clause explicitly imports the `actors` variable. +<3> An xref:clauses/order-by.adoc[`ORDER BY`] clause orders the results by `movieCount` in descending order, ensuring that the `Person` with the highest number of movies appears at the top, and xref:clauses/limit.adoc[`LIMIT] 1` ensures that all other `Person` nodes are discarded. +<4> The second MATCH clause finds all `Movie` nodes associated with the `Person` nodes currently bound to the `actors` variable. + +[NOTE] +The above query uses the xref:functions/aggregating.adoc#functions-collect[`collect()` function]. + +.Result +[role="queryresult",options="header,footer",cols="3* 'Wall Street'; - MATCH (movie:Movie {title: $movieTitle}) +For more information about how Cypher queries work, see xref:clauses/clause-composition.adoc[]. From d20213e0177967ffa4c3bcf3ba3d61bde159373b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Thu, 24 Oct 2024 15:53:00 +0200 Subject: [PATCH 4/9] remove father_of rel --- modules/ROOT/images/graph_match_clause.svg | 2 +- modules/ROOT/pages/clauses/match.adoc | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/ROOT/images/graph_match_clause.svg b/modules/ROOT/images/graph_match_clause.svg index 9426d8918..d2481798f 100644 --- a/modules/ROOT/images/graph_match_clause.svg +++ b/modules/ROOT/images/graph_match_clause.svg @@ -1 +1 @@ -DIRECTEDACTED_INrole:'Gordon Gekko'ACTED_INrole:'Carl Fox'ACTED_INrole:'President Andrew Shepherd'ACTED_INrole:'A.J. MacInerney'ACTED_INrole:'Bud Fox'DIRECTEDFATHER_OFPersonname:'Oliver Stone'Movietitle:'Wall Street'Personname:'Michael Douglas'Personname:'Martin Sheen'Movietitle:'The American President'Personname:'Charlie Sheen'Personname:'Rob Reiner' \ No newline at end of file +DIRECTEDACTED_INrole:'Gordon Gekko'ACTED_INrole:'Carl Fox'ACTED_INrole:'President Andrew Shepherd'ACTED_INrole:'A.J. MacInerney'ACTED_INrole:'Bud Fox'DIRECTEDPersonname:'Oliver Stone'Movietitle:'Wall Street'Personname:'Michael Douglas'Personname:'Martin Sheen'Movietitle:'The American President'Personname:'Charlie Sheen'Personname:'Rob Reiner' diff --git a/modules/ROOT/pages/clauses/match.adoc b/modules/ROOT/pages/clauses/match.adoc index 0f89fca36..272c343c6 100644 --- a/modules/ROOT/pages/clauses/match.adoc +++ b/modules/ROOT/pages/clauses/match.adoc @@ -11,7 +11,7 @@ The `MATCH` clause can specify the nodes, relationships, and properties in a pat The following graph is used for the examples below: -image::graph_match_clause.svg[width="600",role="middle"] +image::graph_match_clause.svg[width="500",role="middle"] To recreate the graph, run the following query against an empty Neo4j database: @@ -30,8 +30,7 @@ CREATE (charlie:Person {name: 'Charlie Sheen'}), (thePresident:Movie {title: 'The American President'}), (martin)-[:ACTED_IN {role: 'A.J. MacInerney'}]->(thePresident), (michael)-[:ACTED_IN {role: 'President Andrew Shepherd'}]->(thePresident), - (rob)-[:DIRECTED]->(thePresident), - (martin)-[:FATHER_OF]->(charlie) + (rob)-[:DIRECTED]->(thePresident) ---- [[find-nodes]] From db449c1aa32805c3a6084f9a8526c90b1367add1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Thu, 24 Oct 2024 21:53:01 +0200 Subject: [PATCH 5/9] corrections --- modules/ROOT/pages/clauses/match.adoc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/ROOT/pages/clauses/match.adoc b/modules/ROOT/pages/clauses/match.adoc index 272c343c6..2f56fc6a6 100644 --- a/modules/ROOT/pages/clauses/match.adoc +++ b/modules/ROOT/pages/clauses/match.adoc @@ -148,7 +148,7 @@ By applying `--`, a pattern will be matched for a relationship with any directio .Find connected nodes using an empty relationship pattern ---- -MATCH (director {name: 'Oliver Stone'})--(n) +MATCH (:Person {name: 'Oliver Stone'})--(n) RETURN n AS connectedNodes ---- @@ -167,7 +167,7 @@ The direction of a relationship in a pattern is indicated by arrows: `-->` or `< .Find all nodes connected to `Oliver Stone` by an outgoing relationship. [source, cypher] ---- -MATCH (:Person {name: 'Oliver Stone'})-->(movie) +MATCH (:Person {name: 'Oliver Stone'})-->(movie:Movie) RETURN movie.title AS movieTitle ---- @@ -187,7 +187,7 @@ It is possible to introduce a variable to a pattern, either for filtering on rel .Find the types of an aliased relationship [source, cypher] ---- -MATCH (:Person {name: 'Oliver Stone'})-[r]->(movie) +MATCH (:Person {name: 'Oliver Stone'})-[r]->() RETURN type(r) AS relType ---- @@ -258,7 +258,7 @@ It is possible to match for a pattern containing one out of several relationship .Relationship pattern including either `ACTED_IN` or `DIRECTED` relationship types [source, cypher] ---- -MATCH ( {title: 'Wall Street'})<-[:ACTED_IN|DIRECTED]-(person) +MATCH (:Movie {title: 'Wall Street'})<-[:ACTED_IN|DIRECTED]-(person:Person) RETURN person.name AS person ---- @@ -283,7 +283,7 @@ A graph pattern can contain several relationship patterns. .Graph pattern including several relationship patterns [source, cypher] ---- -MATCH (charlie {name: 'Charlie Sheen'})-[:ACTED_IN]->(movie)<-[:DIRECTED]-(director) +MATCH (:Person {name: 'Charlie Sheen'})-[:ACTED_IN]->(movie:Movie)<-[:DIRECTED]-(director:Person) RETURN movie.title AS movieTitle, director.name AS director ---- @@ -467,10 +467,10 @@ RETURN actors.name AS actor, movieCount, collect(movies.title) AS movies ---- <1> The `Person` and `Movie` nodes matched in this step are stored in variables. which are then passed on to the second row of the query. -<2> The `movie` variable is here implicitly imported by its occurrence in the `count()` function. +<2> The `movies` variable is here implicitly imported by its occurrence in the `count()` function. The `WITH` clause explicitly imports the `actors` variable. <3> An xref:clauses/order-by.adoc[`ORDER BY`] clause orders the results by `movieCount` in descending order, ensuring that the `Person` with the highest number of movies appears at the top, and xref:clauses/limit.adoc[`LIMIT] 1` ensures that all other `Person` nodes are discarded. -<4> The second MATCH clause finds all `Movie` nodes associated with the `Person` nodes currently bound to the `actors` variable. +<4> The second `MATCH` clause finds all `Movie` nodes associated with the `Person` nodes currently bound to the `actors` variable. [NOTE] The above query uses the xref:functions/aggregating.adoc#functions-collect[`collect()` function]. From 6926d2c8fb2a1d0205e96dbf397ece787a145673 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Fri, 25 Oct 2024 06:39:39 +0200 Subject: [PATCH 6/9] more corrections --- modules/ROOT/pages/clauses/match.adoc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/ROOT/pages/clauses/match.adoc b/modules/ROOT/pages/clauses/match.adoc index 2f56fc6a6..b9d38aae9 100644 --- a/modules/ROOT/pages/clauses/match.adoc +++ b/modules/ROOT/pages/clauses/match.adoc @@ -110,10 +110,10 @@ RETURN n.name AS name, n.title AS title 2+|Rows: 7 |=== -.Node pattern using the `AND` (`&`) and negation (`!`) label expression +.Node pattern using negation (`!`) label expression [source, cypher] ---- -MATCH (n:!Director&!Movie) +MATCH (n:!Movie) RETURN labels(n) AS label, count(n) AS labelCount ---- @@ -236,7 +236,7 @@ It is possible to specify the type of a relationship in a relationship pattern b .Relationship pattern filtering on the `ACTED_IN` relationship type [source, cypher] ---- -MATCH (:Movie {title: 'Wall Street'})<-[:ACTED_IN]-(actor) +MATCH (:Movie {title: 'Wall Street'})<-[:ACTED_IN]-(actor:Person) RETURN actor.name AS actor ---- @@ -452,8 +452,8 @@ RETURN director.name AS director, movie.title AS movieTitle |=== A variable can be implicitly carried over to the following clause by being referenced in another operation. -A variable can also be explicitly passed to the following clause using the `WITH` clause. -If a variable is neither implicitly nor explicitly carried over, it will be discarded and unavailable for reference later in the query. +A variable can also be explicitly passed to the following clause using the xref:clauses/with.adoc[`WITH`] clause. +If a variable is neither implicitly nor explicitly carried over to its following clause, it will be discarded and unavailable for reference later in the query. .Using `WITH` and multiple `MATCH` clauses [source, cypher] From 8fed76e3eba552075d99f9ddebc8b13535c43ac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Fri, 25 Oct 2024 13:20:06 +0200 Subject: [PATCH 7/9] editorial fixes --- modules/ROOT/pages/clauses/match.adoc | 29 ++++++++++++++------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/modules/ROOT/pages/clauses/match.adoc b/modules/ROOT/pages/clauses/match.adoc index b9d38aae9..c252a0425 100644 --- a/modules/ROOT/pages/clauses/match.adoc +++ b/modules/ROOT/pages/clauses/match.adoc @@ -86,8 +86,8 @@ RETURN movie.title |=== -[[match-label-expressions]] -=== MATCH using label expressions +[[match-node-label-expressions]] +=== MATCH using node label expressions .Node pattern using the `OR` (`|`) label expression [source, cypher] @@ -128,7 +128,7 @@ The above query uses the xref:functions/list.adoc#functions-labels[`labels()`] a 2+|Rows: 1 |=== -For a full list of all label expressions supported by Cypher, see xref:patterns/reference.adoc#label-expressions[Patterns -> Label expressions]. +For a list of all label expressions supported by Cypher, see xref:patterns/reference.adoc#label-expressions[Patterns -> Label expressions]. [[find-relationships]] == Find relationships @@ -250,10 +250,10 @@ RETURN actor.name AS actor |Rows: 3 |=== -[[match-on-multiple-relationship-types]] -=== Filter on multiple relationship types +[[match-relationship-type-expressions]] +=== MATCH using relationship type expressions -It is possible to match for a pattern containing one out of several relationship types using the `OR` symbol, `|`. +It is possible to match a pattern containing one of several relationship types using the `OR` symbol, `|`. .Relationship pattern including either `ACTED_IN` or `DIRECTED` relationship types [source, cypher] @@ -273,7 +273,9 @@ RETURN person.name AS person |Rows: 4 |=== -As relationships have exactly one type each, `()-[:A&B]->()` will never match a relationship. +As relationships can only have exactly one type each, `()-[:A&B]->()` will never match a relationship. + +For a list of all relationship type expressions supported by Cypher, see xref:patterns/reference.adoc#label-expressions[Patterns -> Label expressions]. [[multiple-relationships]] === Find multiple relationships @@ -300,7 +302,7 @@ RETURN movie.title AS movieTitle, director.name AS director The `MATCH` clause is often paired with a `WHERE` sub-clause, which adds predicates to refine the patterns, making them more specific. These predicates are part of the pattern itself, not just filters applied after matching. -Thus, the `WHERE` clause should always be placed with its corresponding `MATCH` clause. +Thus, always place the `WHERE` clause with its corresponding `MATCH` clause. .Simple `WHERE` predicate [source, cypher] @@ -426,7 +428,7 @@ For more information about how `MATCH` is used to find patterns of varying compl == Multiple MATCH clauses, the WITH clause, and clause composition -In Cypher, a query’s behavior is defined by its clauses. +In Cypher, the behavior of a query is defined by its clauses. Each clause takes the current graph state and a table of intermediate results, processes them, and passes the updated graph state and results to the next clause. The first clause starts with the graph's initial state and an empty table, while the final clause produces the query's result. @@ -453,7 +455,7 @@ RETURN director.name AS director, movie.title AS movieTitle A variable can be implicitly carried over to the following clause by being referenced in another operation. A variable can also be explicitly passed to the following clause using the xref:clauses/with.adoc[`WITH`] clause. -If a variable is neither implicitly nor explicitly carried over to its following clause, it will be discarded and unavailable for reference later in the query. +If a variable is neither implicitly nor explicitly carried over to its following clause, it will be discarded and is not available for reference later in the query. .Using `WITH` and multiple `MATCH` clauses [source, cypher] @@ -465,11 +467,10 @@ LIMIT 1 // <3> MATCH (actors)-[:ACTED_IN]->(movies) // <4> RETURN actors.name AS actor, movieCount, collect(movies.title) AS movies ---- -<1> The `Person` and `Movie` nodes matched in this step are stored in variables. -which are then passed on to the second row of the query. -<2> The `movies` variable is here implicitly imported by its occurrence in the `count()` function. +<1> The `Person` and `Movie` nodes matched in this step are stored in variables, which are then passed on to the second row of the query. +<2> The `movies` variable is implicitly imported by its occurrence in the `count()` function. The `WITH` clause explicitly imports the `actors` variable. -<3> An xref:clauses/order-by.adoc[`ORDER BY`] clause orders the results by `movieCount` in descending order, ensuring that the `Person` with the highest number of movies appears at the top, and xref:clauses/limit.adoc[`LIMIT] 1` ensures that all other `Person` nodes are discarded. +<3> An xref:clauses/order-by.adoc[`ORDER BY`] clause orders the results by `movieCount` in descending order, ensuring that the `Person` with the highest number of movies appears at the top, and xref:clauses/limit.adoc[`LIMIT] 1` ensures that all other `Person` nodes are discarded. <4> The second `MATCH` clause finds all `Movie` nodes associated with the `Person` nodes currently bound to the `actors` variable. [NOTE] From 3e0207b9ed89f18ec50bdef6e71fde0a735f1e96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Fri, 25 Oct 2024 13:28:37 +0200 Subject: [PATCH 8/9] fix table formatting --- modules/ROOT/pages/clauses/match.adoc | 33 +++++++++++++++------------ 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/modules/ROOT/pages/clauses/match.adoc b/modules/ROOT/pages/clauses/match.adoc index c252a0425..ce33e859d 100644 --- a/modules/ROOT/pages/clauses/match.adoc +++ b/modules/ROOT/pages/clauses/match.adoc @@ -62,7 +62,7 @@ RETURN n | (:Person {"name":"Rob Reiner"}) | (:Movie {"title":"Wall Street"}) | (:Movie {"title":"The American President"}) -|Rows: 7 +1+d| Rows: 7 |=== @@ -82,7 +82,7 @@ RETURN movie.title | movie.title | "Wall Street" | "The American President" -|Rows: 2 +1+d| Rows: 2 |=== @@ -107,7 +107,7 @@ RETURN n.name AS name, n.title AS title | "Rob Reiner" | | | "Wall Street" | | "The American President" -2+|Rows: 7 +2+d| Rows: 7 |=== .Node pattern using negation (`!`) label expression @@ -125,7 +125,7 @@ The above query uses the xref:functions/list.adoc#functions-labels[`labels()`] a |=== | label | labelCount | ["Person"] | 5 -2+|Rows: 1 +2+d| Rows: 1 |=== For a list of all label expressions supported by Cypher, see xref:patterns/reference.adoc#label-expressions[Patterns -> Label expressions]. @@ -147,6 +147,7 @@ Read more about this behavior in the section on xref::patterns/reference.adoc#gr By applying `--`, a pattern will be matched for a relationship with any direction and without any filtering on relationship types or properties. .Find connected nodes using an empty relationship pattern +[source, cypher] ---- MATCH (:Person {name: 'Oliver Stone'})--(n) RETURN n AS connectedNodes @@ -157,6 +158,8 @@ RETURN n AS connectedNodes |=== | connectedNodes | (:Movie {title: "Wall Street"}) + +1+d| Rows: 1 |=== [[directed-relationship-patterns]] @@ -176,7 +179,7 @@ RETURN movie.title AS movieTitle |=== | movieTitle | "Wall Street" -|Rows: 1 +1+d| Rows: 1 |=== [[relationship-variables]] @@ -199,7 +202,7 @@ The above query uses the xref:functions/scalar.adoc#functions-type[`type()` func |=== | relType | "DIRECTED" -|Rows: 1 +1+d| Rows: 1 |=== [[undirected-relationships]] @@ -225,7 +228,7 @@ RETURN a, b | (:Person {"name":"Charlie Sheen"}) | (:Movie {"title":"Wall Street"}) -2+|Rows: 2 +2+d| Rows: 2 |=== [[match-on-relationship-type]] @@ -247,7 +250,7 @@ RETURN actor.name AS actor | "Michael Douglas" | "Martin Sheen" | "Charlie Sheen" -|Rows: 3 +1+d| Rows: 3 |=== [[match-relationship-type-expressions]] @@ -270,7 +273,7 @@ RETURN person.name AS person | "Michael Douglas" | "Martin Sheen" | "Charlie Sheen" -|Rows: 4 +1+d| Rows: 4 |=== As relationships can only have exactly one type each, `()-[:A&B]->()` will never match a relationship. @@ -294,7 +297,7 @@ RETURN movie.title AS movieTitle, director.name AS director |=== | movieTitle | director | "Wall Street" | "Oliver Stone" -2+|Rows: 1 +2+d| Rows: 1 |=== [[where-predicates]] @@ -317,7 +320,7 @@ RETURN movie.title AS movieTitle |=== | movieTitle | "Wall Street" -|Rows: 1 +1+d| Rows: 1 |=== .More complex `WHERE` predicate @@ -338,7 +341,7 @@ The above query uses an xref:subqueries/existential.adoc[`EXISTS` subquery]. |=== | movieTitle | "The American President" -|Rows: 1 +1+d| Rows: 1 |=== For more information, see the xref:clauses/where.adoc[`WHERE`] page. @@ -376,7 +379,7 @@ The above query uses the xref:syntax/operators.adoc#query-operator-comparison-st | "Charlie Sheen" | "Bud Fox" | "Martin Sheen" | "Carl Fox" -2+|Rows: 2 +2+d|Rows: 2 |=== For more information about how to set parameters, see xref:syntax/parameters.adoc[Syntax -> Parameters]. @@ -402,7 +405,7 @@ RETURN path | (:Person {name: "Martin Sheen"})-[:ACTED_IN {role: "A.J. MacInerney"}]->(:Movie {title: "The American President"}) | (:Person {name: "Michael Douglas"})-[:ACTED_IN {role: "Gordon Gekko"}]->(:Movie {title: "Wall Street"}) | (:Person {name: "Michael Douglas"})-[:ACTED_IN {role: "President Andrew Shepherd"}]->(:Movie {title: "The American President"}) -| Rows: 5 +1+d| Rows: 5 |=== @@ -421,7 +424,7 @@ RETURN path | (:Person {name: "Charlie Sheen"})-[:ACTED_IN {role: "Bud Fox"}]->(:Movie {title: "Wall Street"})<-[:DIRECTED]-(:Person {name: "Oliver Stone"}) | (:Person {name: "Martin Sheen"})-[:ACTED_IN {role: "Carl Fox"}]->(:Movie {title: "Wall Street"})<-[:DIRECTED]-(:Person {name: "Oliver Stone"}) | (:Person {name: "Michael Douglas"})-[:ACTED_IN {role: "Gordon Gekko"}]->(:Movie {title: "Wall Street"})<-[:DIRECTED]-(:Person {name: "Oliver Stone"}) -|Rows: 3 +1+d| Rows: 3 |=== For more information about how `MATCH` is used to find patterns of varying complexity (including xref:patterns/variable-length-patterns.adoc#quantified-path-patterns[quantified path patterns], xref:patterns/variable-length-patterns.adoc#quantified-relationships[quantified relationships], and the xref:patterns/shortest-paths.adoc[shortest paths] between nodes), see the section on xref::patterns/index.adoc[Patterns]. From 036cb1188f956e08aba2bb21f91c960979b05cea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Fri, 25 Oct 2024 13:50:25 +0200 Subject: [PATCH 9/9] final --- modules/ROOT/pages/clauses/match.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ROOT/pages/clauses/match.adoc b/modules/ROOT/pages/clauses/match.adoc index ce33e859d..f04bf857d 100644 --- a/modules/ROOT/pages/clauses/match.adoc +++ b/modules/ROOT/pages/clauses/match.adoc @@ -433,7 +433,7 @@ For more information about how `MATCH` is used to find patterns of varying compl In Cypher, the behavior of a query is defined by its clauses. Each clause takes the current graph state and a table of intermediate results, processes them, and passes the updated graph state and results to the next clause. -The first clause starts with the graph's initial state and an empty table, while the final clause produces the query's result. +The first clause starts with the graph's initial state and an empty table, while the final clause produces the query result. .Chaining consecutive `MATCH` clauses [source, cypher]