From c2fda9568c27c70da7f5d9aac1b75c6acd5c3bc9 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 Apr 2025 15:03:57 +0200 Subject: [PATCH 1/6] Add epocmillis cheat sheet tags (#1227) --- .../ROOT/pages/functions/temporal/index.adoc | 69 ++++++++++++------- 1 file changed, 45 insertions(+), 24 deletions(-) diff --git a/modules/ROOT/pages/functions/temporal/index.adoc b/modules/ROOT/pages/functions/temporal/index.adoc index 3da0ab037..3890c90ad 100644 --- a/modules/ROOT/pages/functions/temporal/index.adoc +++ b/modules/ROOT/pages/functions/temporal/index.adoc @@ -482,7 +482,6 @@ RETURN theDate ====== .Query -// tag::functions_temporal_date_transaction[] [source, cypher] ---- UNWIND [ @@ -492,7 +491,6 @@ date({year: 1984}) ] AS theDate RETURN theDate ---- -// end::functions_temporal_date_transaction[] .Result [role="queryresult",options="header,footer",cols="1* Date: Tue, 14 Jan 2025 13:25:25 +0100 Subject: [PATCH 2/6] fixes --- modules/ROOT/pages/clauses/finish.adoc | 4 +- modules/ROOT/pages/clauses/foreach.adoc | 48 ++++++++++++++++++- modules/ROOT/pages/clauses/limit.adoc | 4 ++ modules/ROOT/pages/clauses/load-csv.adoc | 17 ++++++- modules/ROOT/pages/clauses/match.adoc | 10 ++++ .../ROOT/pages/clauses/optional-match.adoc | 2 + modules/ROOT/pages/clauses/order-by.adoc | 8 ++++ modules/ROOT/pages/clauses/return.adoc | 12 +++++ modules/ROOT/pages/clauses/skip.adoc | 6 +++ modules/ROOT/pages/clauses/unwind.adoc | 6 +++ modules/ROOT/pages/clauses/use.adoc | 6 ++- modules/ROOT/pages/clauses/where.adoc | 4 ++ modules/ROOT/pages/clauses/with.adoc | 2 + .../ROOT/pages/functions/temporal/index.adoc | 8 ++-- .../composed-queries/combined-queries.adoc | 4 ++ 15 files changed, 133 insertions(+), 8 deletions(-) diff --git a/modules/ROOT/pages/clauses/finish.adoc b/modules/ROOT/pages/clauses/finish.adoc index 21413fc51..814575c39 100644 --- a/modules/ROOT/pages/clauses/finish.adoc +++ b/modules/ROOT/pages/clauses/finish.adoc @@ -2,17 +2,19 @@ [[query-finish]] = FINISH -A query ending in `FINISH` — instead of `RETURN` — has no result but executes all its side effects. +A query ending in `FINISH` -- instead of `RETURN` -- has no result but executes all its side effects. `FINISH` was introduced as part of Cypher's xref:appendix/gql-conformance/index.adoc[]. The following read query successfully executes but has no results: .Query +// tag::clauses_finish_match[] [source, cypher] ---- MATCH (p:Person) FINISH ---- +// end::clauses_finish_match[] The following query has no result but creates one node with the label `Person`: diff --git a/modules/ROOT/pages/clauses/foreach.adoc b/modules/ROOT/pages/clauses/foreach.adoc index b594ecace..2132954e6 100644 --- a/modules/ROOT/pages/clauses/foreach.adoc +++ b/modules/ROOT/pages/clauses/foreach.adoc @@ -33,15 +33,17 @@ CREATE [[foreach-mark-all-nodes-along-a-path]] == Mark all nodes along a path -This query will set the property `marked` to `true` on all nodes along a path. +This query sets the property `marked` to `true` on all nodes along a path. .Query +// tag::clauses_foreach_node[] [source, cypher, indent=0] ---- MATCH p=(start)-[*]->(finish) WHERE start.name = 'A' AND finish.name = 'D' FOREACH (n IN nodes(p) | SET n.marked = true) ---- +// end::clauses_foreach_node[] .Result [role="queryresult",options="footer",cols="1*(finish) +WHERE start.name = 'A' AND finish.name = 'D' +FOREACH ( r IN relationships(p) | SET r.marked = true ) +---- +// end::clauses_foreach_relationship[] + +.Result +[role="queryresult",options="footer",cols="1*() RETURN type(r) AS relType ---- +// end::clauses_match_relationship_types[] [NOTE] The above query uses the xref:functions/scalar.adoc#functions-type[`type()` function]. @@ -238,11 +244,13 @@ RETURN a, b It is possible to specify the type of a relationship in a relationship pattern by using a colon (`:`) before the relationship type. .Relationship pattern filtering on the `ACTED_IN` relationship type +// tag::clauses_match_relationship[] [source, cypher] ---- MATCH (:Movie {title: 'Wall Street'})<-[:ACTED_IN]-(actor:Person) RETURN actor.name AS actor ---- +// end::clauses_match_relationship[] .Result [source, role="queryresult",options="header,footer",cols="1*(movie:Movie) RETURN path ---- +// end::clauses_match_path[] .Result [role="queryresult",options="header,footer",cols="1*() RETURN p.name, r ---- +// end::clauses_optional_match[] .Result [role="queryresult",options="header,footer",cols="2*(m) RETURN type(r) ---- +// end::clauses_return_relationship_type[] .Result [role="queryresult",options="header,footer",cols="1*(m) RETURN * ---- +// end::clauses_return_all_elements[] This returns the two nodes, and the two possible paths between them. @@ -149,11 +157,13 @@ d|Rows: 1 Names of returned columns can be renamed using the `AS` operator: .Query +// tag::clauses_return_with_column_alias[] [source, cypher] ---- MATCH (p:Person {name: 'Keanu Reeves'}) RETURN p.nationality AS citizenship ---- +// end::clauses_return_with_column_alias[] Returns the `nationality` property of `'Keanu Reeves'`, but the column is renamed to `citizenship`. @@ -220,11 +230,13 @@ Returns a predicate, a literal and function call with a pattern expression param `DISTINCT` retrieves only unique rows for the columns that have been selected for output. .Query +// tag::clauses_return_distinct[] [source, cypher] ---- MATCH (p:Person {name: 'Keanu Reeves'})-->(m) RETURN DISTINCT m ---- +// end::clauses_return_distinct[] The `Movie` node `'Man of Tai Chi'` is returned by the query, but only once (without the `DISTINCT` operator it would have been returned twice because there are two relationships going to it from `'Keanu Reeves'`): diff --git a/modules/ROOT/pages/clauses/skip.adoc b/modules/ROOT/pages/clauses/skip.adoc index b4c4ecbee..b8436b80d 100644 --- a/modules/ROOT/pages/clauses/skip.adoc +++ b/modules/ROOT/pages/clauses/skip.adoc @@ -69,6 +69,7 @@ d|Rows: 2 The following query returns the middle two rows, with `SKIP` skipping the first and xref:clauses/limit.adoc[`LIMIT`] removing the final two. .Query +// tag::clauses_skip[] [source, cypher] ---- MATCH (n) @@ -77,6 +78,7 @@ ORDER BY n.name SKIP 1 LIMIT 2 ---- +// end::clauses_skip[] .Result [role="queryresult",options="header,footer",cols="1*(b WHERE b:Person) | b.name] AS friends ---- +// end::clauses_where_pattern_comprehension[] .Result [role="queryresult",options="header,footer",cols="1*(:Product {name: 'Chocolate'}) WITH c AS customer RETURN customer.firstName AS chocolateCustomer ---- +// end::clauses_with_wildcard[] .Result [role="queryresult",options="header,footer",cols="1* Date: Wed, 27 Nov 2024 12:50:51 +0100 Subject: [PATCH 3/6] Add cheat sheet tags for dynamic labels/types (#1117) (Also fixes 2 minor errors) Corresponding Cheat sheet PR: https://github.com/neo4j/docs-cheat-sheet/pull/202 --- modules/ROOT/pages/clauses/create.adoc | 2 ++ modules/ROOT/pages/clauses/load-csv.adoc | 6 ++++-- modules/ROOT/pages/clauses/match.adoc | 8 +++++++- modules/ROOT/pages/clauses/merge.adoc | 2 ++ 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/modules/ROOT/pages/clauses/create.adoc b/modules/ROOT/pages/clauses/create.adoc index 57843ddae..f07d0a235 100644 --- a/modules/ROOT/pages/clauses/create.adoc +++ b/modules/ROOT/pages/clauses/create.adoc @@ -234,6 +234,7 @@ This is because a relationship can only have exactly one type. ---- .Create nodes and relationships using dynamic node labels and relationship types +// tag::clauses_create_dynamic_create[] [source, cypher] ---- CREATE (greta:$($nodeLabels) {name: 'Greta Gerwig'}) @@ -242,6 +243,7 @@ UNWIND $movies AS movieTitle CREATE (greta)-[rel:$($relType)]->(m:Movie {title: movieTitle}) RETURN greta.name AS name, labels(greta) AS labels, type(rel) AS relType, collect(m.title) AS movies ---- +// end::clauses_create_dynamic_create[] .Result [role="queryresult",options="footer",cols="4* Protecting against Cypher injection]). .bands-with-headers.csv -[source, csv, filename="artists-with-headers.csv"] +[source, csv, filename="bands-with-headers.csv"] ---- Id,Label,Name 1,Band,The Beatles @@ -322,12 +322,14 @@ Id,Label,Name ---- .Query -[source, cypher, role=test-skip] +// tag::clauses_load_csv_dynamic_columns[] +[source, cypher] ---- LOAD CSV WITH HEADERS FROM 'file:///bands-with-headers.csv' AS line MERGE (n:$(line.Label) {name: line.Name}) RETURN n AS bandNodes ---- +// end::clauses_load_csv_dynamic_columns[] .Result [role="queryresult",options="header,footer",cols="1*() RETURN relationshipType, count(r) AS relationshipCount ---- +// end::clauses_match_dynamic_match_variable[] + .Result [role="queryresult",options="header,footer",cols="2*(m:Movie {title: movieTitle}) RETURN greta.name AS name, labels(greta) AS labels, type(rel) AS relType, collect(m.title) AS movies ---- +// end::clauses_merge_dynamic_merge[] .Result [role="queryresult",options="footer",cols="4* Date: Tue, 3 Dec 2024 15:12:28 +0100 Subject: [PATCH 4/6] Cheat sheet tags for patterns and label expressions (#1125) Cheat Sheet PR: https://github.com/neo4j/docs-cheat-sheet/pull/203 --- modules/ROOT/pages/clauses/match.adoc | 9 +++++++++ modules/ROOT/pages/patterns/fixed-length-patterns.adoc | 8 +++++++- modules/ROOT/pages/patterns/non-linear-patterns.adoc | 6 ++++++ modules/ROOT/pages/patterns/shortest-paths.adoc | 8 ++++++++ .../ROOT/pages/patterns/variable-length-patterns.adoc | 9 +++++++++ 5 files changed, 39 insertions(+), 1 deletion(-) diff --git a/modules/ROOT/pages/clauses/match.adoc b/modules/ROOT/pages/clauses/match.adoc index ff82ad269..7596a47a0 100644 --- a/modules/ROOT/pages/clauses/match.adoc +++ b/modules/ROOT/pages/clauses/match.adoc @@ -94,11 +94,14 @@ RETURN movie.title === MATCH using node label expressions .Node pattern using the `OR` (`|`) label expression +// tag::clauses_match_label_expression_or[] [source, cypher] ---- MATCH (n:Movie|Person) RETURN n.name AS name, n.title AS title ---- +// end::clauses_match_label_expression_or[] + .Result [role="queryresult",options="header,footer",cols="2*(:Station {name: 'Denmark Hill'}) RETURN s.departs AS departureTime ---- +// end::patterns_fixed_length_patterns_path_pattern[] .Result [role="queryresult",options="header,footer",cols="1*(:Station { name: 'Clapham Junction' }) RETURN d.departs AS departureTime, a.arrives AS arrivalTime ---- +// end::patterns_variable_length_patterns_qpp[] + .Result [role="queryresult",options="header,footer",cols="2*` and not the node patterns abutting it. More generally, where a path pattern contained in a quantified path pattern has the following form: @@ -523,6 +529,7 @@ In this example, an inline predicate can be added that takes advantage of the ge To compose the predicate, the xref:functions/spatial.adoc#functions-distance[point.distance()] function is used to compare the distance between the left-hand `Station` (`a`) and the right-hand `Station` (`b`) for each node-pair along the path to the destination `North Dulwich`: .Query +// tag::patterns_variable_length_patterns_predicates_in_qpp[] [source,cypher] ---- MATCH (bfr:Station {name: "London Blackfriars"}), @@ -534,6 +541,8 @@ MATCH p = (bfr) RETURN reduce(acc = 0, r in relationships(p) | round(acc + r.distance, 2)) AS distance ---- +// end::patterns_variable_length_patterns_predicates_in_qpp[] + .Result [role="queryresult",options="header,footer",cols="m"] From f926d6013b5de1981c35382351597bf712ca2882 Mon Sep 17 00:00:00 2001 From: Richard Sill <156673635+rsill-neo4j@users.noreply.github.com> Date: Tue, 14 Jan 2025 11:24:21 +0100 Subject: [PATCH 5/6] fixes --- modules/ROOT/pages/clauses/where.adoc | 4 ++++ modules/ROOT/pages/clauses/with.adoc | 2 ++ 2 files changed, 6 insertions(+) diff --git a/modules/ROOT/pages/clauses/where.adoc b/modules/ROOT/pages/clauses/where.adoc index 156fa45c4..3495bcce7 100644 --- a/modules/ROOT/pages/clauses/where.adoc +++ b/modules/ROOT/pages/clauses/where.adoc @@ -69,6 +69,7 @@ MATCH (n:Person) WHERE n.age < 35 RETURN n.name AS name, n.age AS age ---- +// end::clauses_where_boolean_operations[] .Result [role="queryresult",options="header,footer",cols="2*(f) WHERE k.since < 2000 RETURN f.name AS oldFriend ---- +// end::clauses_where_relationship_property[] .Result [role="queryresult",options="header,footer",cols="1*(chocolate), (foodies)-[:SUPPLIES]->(coffee) ---- +// end::clauses_with_variables[] [[create-new-variables]] == Create new variables @@ -130,6 +131,7 @@ WITH c.name AS chocolateCustomers RETURN chocolateCustomers, p.price AS chocolatePrice ---- +// end::clauses_with_wildcard[] .Error message [source, error] From 76c904b4b11065667324967bf8baa17c9bead9d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Wed, 23 Apr 2025 15:35:35 +0200 Subject: [PATCH 6/6] fixes --- modules/ROOT/pages/clauses/load-csv.adoc | 3 +-- modules/ROOT/pages/clauses/where.adoc | 2 +- modules/ROOT/pages/clauses/with.adoc | 23 +++++++++++++++++++---- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/modules/ROOT/pages/clauses/load-csv.adoc b/modules/ROOT/pages/clauses/load-csv.adoc index d4868ad5e..dd75bd942 100644 --- a/modules/ROOT/pages/clauses/load-csv.adoc +++ b/modules/ROOT/pages/clauses/load-csv.adoc @@ -708,8 +708,7 @@ person_tmdbId,bio,born,bornIn,died,person_imdbId,name,person_poster,person_url ---- [NOTE] -The query below uses a xref:subqueries/call-subquery.adoc#variable-scope-clause[variable scope clause] (introduced in Neo4j 5.23) to import variables into the `CALL` subquery. -If you are using an older version of Neo4j, use an xref:subqueries/call-subquery.adoc#importing-with[importing `WITH` clause] instead. +The below query uses a xref:subqueries/call-subquery.adoc#variable-scope-clause[variable scope clause] to import variables into the `CALL` subquery. .Query // tag::clauses_load_csv_transactions[] diff --git a/modules/ROOT/pages/clauses/where.adoc b/modules/ROOT/pages/clauses/where.adoc index 3495bcce7..8a34798f4 100644 --- a/modules/ROOT/pages/clauses/where.adoc +++ b/modules/ROOT/pages/clauses/where.adoc @@ -69,7 +69,6 @@ MATCH (n:Person) WHERE n.age < 35 RETURN n.name AS name, n.age AS age ---- -// end::clauses_where_boolean_operations[] .Result [role="queryresult",options="header,footer",cols="2*(f) diff --git a/modules/ROOT/pages/clauses/with.adoc b/modules/ROOT/pages/clauses/with.adoc index 7f6c8faae..415a1f17b 100644 --- a/modules/ROOT/pages/clauses/with.adoc +++ b/modules/ROOT/pages/clauses/with.adoc @@ -61,7 +61,6 @@ CREATE (techCorp:Supplier {name: 'TechCorp', email: 'contact@techcorp.com'}), (foodies)-[:SUPPLIES]->(chocolate), (foodies)-[:SUPPLIES]->(coffee) ---- -// end::clauses_with_variables[] [[create-new-variables]] == Create new variables @@ -89,14 +88,14 @@ In the below example, the `WITH` clause binds all matched `Customer` nodes to a The bound nodes are `MAP` values which can then be referenced from the new variable. .Create a new variable bound to matched nodes -// tag::clauses_with_wildcard[] +// tag::clauses_with_new_variable[] [source, cypher] ---- MATCH (c:Customer)-[:BUYS]->(:Product {name: 'Chocolate'}) WITH c AS customer RETURN customer.firstName AS chocolateCustomer ---- -// end::clauses_with_wildcard[] +// end::clauses_with_new_variable[] .Result [role="queryresult",options="header,footer",cols="1*(product:Product) @@ -148,6 +147,7 @@ RETURN supplier.name AS company, type(r) AS relType, product.name AS product ---- +// end::clauses_with_all_variables[] .Result [role="queryresult",options="header,footer",cols="3*(chocolate:Product {name: 'Chocolate'}) @@ -208,6 +211,7 @@ WITH customer.firstName || ' ' || customer.lastName AS customerFullName, RETURN customerFullName, chocolateNetPrice ---- +// end::clauses_with_bind_values[] .Result [role="queryresult",options="header,footer",cols="2*(p:Product) @@ -278,6 +285,8 @@ RETURN customer, productsBought ORDER BY totalSpent DESC ---- +// end::clauses_with_aggregations[] + .Result [role="queryresult",options="header,footer", cols="3*(p:Product) @@ -407,6 +419,7 @@ RETURN c.firstName AS customer, totalSpent, c.topSpender AS topSpender ---- +// end::clauses_with_ordering_pagination[] [role="queryresult",options="header,footer", cols="3*(p:Product)<-[:BUYS]-(c:Customer) @@ -520,6 +534,7 @@ RETURN s.name AS supplier, totalSales, uniqueCustomers ---- +// end::clauses_with_filtering[] [role="queryresult",options="header,footer", cols="3*