From edec2969a8dabe0b0c63de325fb7b3b904599857 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Wed, 30 Oct 2024 14:42:51 +0100 Subject: [PATCH 01/17] match and some of create --- modules/ROOT/pages/clauses/create.adoc | 27 +++++ modules/ROOT/pages/clauses/match.adoc | 142 +++++++++++++++++++++++++ modules/ROOT/pages/clauses/remove.adoc | 7 +- modules/ROOT/pages/clauses/set.adoc | 4 +- 4 files changed, 174 insertions(+), 6 deletions(-) diff --git a/modules/ROOT/pages/clauses/create.adoc b/modules/ROOT/pages/clauses/create.adoc index 9749ac375..ccbe9e3a0 100644 --- a/modules/ROOT/pages/clauses/create.adoc +++ b/modules/ROOT/pages/clauses/create.adoc @@ -205,6 +205,33 @@ Nodes created: 2 + Properties set: 4 |=== +[role=label--new-5.26] +[[dynamic-create]] +== Dynamically CREATE nodes and relationships + +Nodes and relationships can be created dynamically by using variables or parameters for the node labels and relationship types. + +.Syntax for creating nodes and relationships dynamically +[source, syntax] +---- +CREATE (n:$()), +CREATE ()-[r:$()]->() +---- + +[NOTE] +Using dynamic node labels and relationship types can prevent Cypher injection (a type of security vulnerability where an attacker injects malicious code into Cypher queries, potentially allowing unauthorized access or manipulation of a database). +For more information, see link:https://neo4j.com/developer/kb/protecting-against-cypher-injection/[Neo4j Knowledge Base -> Protecting against Cypher injection]. + +.Create a node using dynamic labels +[source, cypher] +---- +UNWIND ["Person", "Director"] AS nodeLabels +CREATE (n:$(nodeLabels) {name: 'Greta Gerwig'}) +RETURN labels(n) AS createdLabels +---- + + + [role=label--new-5.18] [[insert-as-synonym-of-create]] == `INSERT` as a synonym of `CREATE` diff --git a/modules/ROOT/pages/clauses/match.adoc b/modules/ROOT/pages/clauses/match.adoc index 35f568d88..3468ba434 100644 --- a/modules/ROOT/pages/clauses/match.adoc +++ b/modules/ROOT/pages/clauses/match.adoc @@ -490,3 +490,145 @@ The above query uses the xref:functions/aggregating.adoc#functions-collect[`coll For more information about how Cypher queries work, see xref:clauses/clause-composition.adoc[]. +[role=label--new-5.26] +[[dynamic-match]] +== Dynamically MATCH nodes and relationships + +Nodes and relationships can be matched dynamically by using variables or parameters for the node labels and relationship types in the graph pattern. + +.Syntax for matching node labels dynamically +[source, syntax] +---- +MATCH (n:$()) +MATCH (n:$any()) +MATCH (n:$all()) +---- + +.Syntax for matching relationship types dynamically +[source, syntax] +---- +MATCH ()-[r:$())]->() +MATCH ()-[r:$any()]->() +MATCH ()-[r:$all())]->() +---- + +The expression must evaluate to a `STRING NOT NULL | LIST NOT NULL` value, or a type mismatch error is raised. + +[NOTE] +Using dynamic node labels and relationship types can prevent Cypher injection (a type of security vulnerability where an attacker injects malicious code into Cypher queries, potentially allowing unauthorized access or manipulation of a database). +For more information, see link:https://neo4j.com/developer/kb/protecting-against-cypher-injection/[Neo4j Knowledge Base -> Protecting against Cypher injection]. + +.Match labels dynamically using the `all()` function +[source, cypher] +---- +WITH "Movie" AS label +MATCH (movie:$all(label)) +RETURN movie AS movieNodes +---- + +.Result +[role="queryresult",options="header,footer",cols="1*` to an `all()` function evaluating a relationship pattern using dynamic relationship types, the list cannot contain more than one element. +This is because a relationship can only have exactly one type. + +.Attempting to match relationship patterns using more than one relationship type will not return any results +[source, cypher] +---- +MATCH ()-[r:$all(["ACTED_IN", "DIRECTED"])]->() +RETURN r +---- + +.Warning +[source, warning] +---- +Warning: The query contains a relationship type expression that cannot be satisfied. +---- + +.Match nodes dynamically using the `any()` function +[source, cypher] +---- +MATCH (n:$any(["Movie", "Person"]))-[:ACTED_IN|DIRECTED]->(m:Movie) +RETURN labels(n) AS labels, n.name AS person, collect(m.title) AS movies +---- + +[NOTE] +The xref:functions/predicate.adoc#functions-any[`any()`] function matches nodes that have any of the specified labels. + +.Result +[role="queryresult",options="header,footer",cols="3* Date: Thu, 31 Oct 2024 10:06:47 +0100 Subject: [PATCH 02/17] =?UTF-8?q?more=C3=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/ROOT/pages/clauses/create.adoc | 37 +++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/modules/ROOT/pages/clauses/create.adoc b/modules/ROOT/pages/clauses/create.adoc index ccbe9e3a0..ab15462e8 100644 --- a/modules/ROOT/pages/clauses/create.adoc +++ b/modules/ROOT/pages/clauses/create.adoc @@ -222,14 +222,43 @@ CREATE ()-[r:$()]->() Using dynamic node labels and relationship types can prevent Cypher injection (a type of security vulnerability where an attacker injects malicious code into Cypher queries, potentially allowing unauthorized access or manipulation of a database). For more information, see link:https://neo4j.com/developer/kb/protecting-against-cypher-injection/[Neo4j Knowledge Base -> Protecting against Cypher injection]. -.Create a node using dynamic labels +.Parameters +[source, parameters] +---- +{ + "nodeLabels": ["Person", "Director"] + "relType": "DIRECTED" + "movies": ["Ladybird", "Little Women", "Barbie"] +} +---- + +.Create nodes and relationships using dynamic node labels and relationship types [source, cypher] ---- -UNWIND ["Person", "Director"] AS nodeLabels -CREATE (n:$(nodeLabels) {name: 'Greta Gerwig'}) -RETURN labels(n) AS createdLabels +CREATE (greta:$all(nodeLabels) {name: 'Greta Gerwig'}) +WITH greta, $movies AS movies, $relType AS relType +UNWIND movies AS movieTitle +CREATE (m:Movie {title: movieTitle}) +CREATE (greta)-[:$(relType)]->(m) +RETURN greta.name AS name, labels(greta) AS gretaLabels, collect(m.title) AS moviesDirected ---- +.Result +[role="queryresult",options="footer",cols="2* Date: Fri, 1 Nov 2024 15:19:32 +0100 Subject: [PATCH 03/17] add load csv and additions page entry --- modules/ROOT/pages/clauses/create.adoc | 30 +++++---- modules/ROOT/pages/clauses/load-csv.adoc | 37 +++++++++++ modules/ROOT/pages/clauses/match.adoc | 14 +++-- modules/ROOT/pages/clauses/merge.adoc | 63 +++++++++++++++++++ ...ions-additions-removals-compatibility.adoc | 45 ++++++++++++- 5 files changed, 171 insertions(+), 18 deletions(-) diff --git a/modules/ROOT/pages/clauses/create.adoc b/modules/ROOT/pages/clauses/create.adoc index ab15462e8..3038b2243 100644 --- a/modules/ROOT/pages/clauses/create.adoc +++ b/modules/ROOT/pages/clauses/create.adoc @@ -207,9 +207,9 @@ Properties set: 4 [role=label--new-5.26] [[dynamic-create]] -== Dynamically CREATE nodes and relationships +== CREATE nodes and relationships using dynamic node labels and relationship types -Nodes and relationships can be created dynamically by using variables or parameters for the node labels and relationship types. +Node labels and relationship types can be referenced dynamically in parameters and variables when creating nodes and relationships. .Syntax for creating nodes and relationships dynamically [source, syntax] @@ -218,6 +218,8 @@ CREATE (n:$()), CREATE ()-[r:$()]->() ---- +The expression must evaluate to a `STRING NOT NULL | LIST NOT NULL` value. + [NOTE] Using dynamic node labels and relationship types can prevent Cypher injection (a type of security vulnerability where an attacker injects malicious code into Cypher queries, potentially allowing unauthorized access or manipulation of a database). For more information, see link:https://neo4j.com/developer/kb/protecting-against-cypher-injection/[Neo4j Knowledge Base -> Protecting against Cypher injection]. @@ -226,8 +228,8 @@ For more information, see link:https://neo4j.com/developer/kb/protecting-against [source, parameters] ---- { - "nodeLabels": ["Person", "Director"] - "relType": "DIRECTED" + "nodeLabels": ["Person", "Director"], + "relType": "DIRECTED", "movies": ["Ladybird", "Little Women", "Barbie"] } ---- @@ -235,16 +237,15 @@ For more information, see link:https://neo4j.com/developer/kb/protecting-against .Create nodes and relationships using dynamic node labels and relationship types [source, cypher] ---- -CREATE (greta:$all(nodeLabels) {name: 'Greta Gerwig'}) -WITH greta, $movies AS movies, $relType AS relType -UNWIND movies AS movieTitle -CREATE (m:Movie {title: movieTitle}) -CREATE (greta)-[:$(relType)]->(m) +CREATE (greta:$($nodeLabels) {name: 'Greta Gerwig'}) +WITH greta +UNWIND $movies AS movieTitle +CREATE (greta)-[:$($relType)]->(m:Movie {title: movieTitle}) RETURN greta.name AS name, labels(greta) AS gretaLabels, collect(m.title) AS moviesDirected ---- .Result -[role="queryresult",options="footer",cols="2*)]->() MATCH ()-[r:$all())]->() ---- -The expression must evaluate to a `STRING NOT NULL | LIST NOT NULL` value, or a type mismatch error is raised. +The expression must evaluate to a `STRING NOT NULL | LIST NOT NULL` value. [NOTE] Using dynamic node labels and relationship types can prevent Cypher injection (a type of security vulnerability where an attacker injects malicious code into Cypher queries, potentially allowing unauthorized access or manipulation of a database). @@ -629,6 +629,8 @@ RETURN relationshipType, count(r) AS relationshipCount For more information, see: -* xref:clauses/set.adoc#dynamic-set-property[Dynamically setting or updating a property] and xref:clauses/set.adoc#dynamic-set-node-label[Dynamically setting a node label] -* xref:clauses/remove.adoc#dynamic-remove-property[Dynamically removing a property] and xref:clauses/remove.adoc#dynamic-remove-node-label[Dynamically removing a node label] -* xref:clauses/create.adoc#dynamic-create[Dynamically creating nodes and relationships] \ No newline at end of file +* xref:clauses/set.adoc#dynamic-set-property[Dynamically `SET` or updating a property] and xref:clauses/set.adoc#dynamic-set-node-label[Dynamically `SET` a node label] +* xref:clauses/remove.adoc#dynamic-remove-property[Dynamically `REMOVE` a property] and xref:clauses/remove.adoc#dynamic-remove-node-label[Dynamically `REMOVE` a node label] +* xref:clauses/create.adoc#dynamic-create[`CREATE` nodes and relationships using dynamic node labels and relationship types] +* xref:clauses/merge.adoc#dynamic-merge[`MERGE` nodes and relationships using dynamic node labels and relationship types] +* xref:clauses/load-csv.adoc#dynamic-columns[Import CSV using dynamic columns] \ No newline at end of file diff --git a/modules/ROOT/pages/clauses/merge.adoc b/modules/ROOT/pages/clauses/merge.adoc index 669409c6a..c60873809 100644 --- a/modules/ROOT/pages/clauses/merge.adoc +++ b/modules/ROOT/pages/clauses/merge.adoc @@ -683,3 +683,66 @@ RETURN person.name, person.bornIn, person.chauffeurName | person.name | person.bornIn | person.chauffeurName | "Keanu Reeves" | "Beirut" | "Eric Brown" |=== + +[role=label--new-5.26] +[[dynamic-merge]] +== MERGE nodes and relationships using dynamic node labels and relationship types + +Node labels and relationship types can be referenced dynamically in parameters and variables when merging nodes and relationships. + +.Syntax for merging nodes and relationships dynamically +[source, syntax] +---- +MERGE (n:$()), +MERGE ()-[r:$()]->() +---- + +The expression must evaluate to a `STRING NOT NULL | LIST NOT NULL` value. + +[NOTE] +Using dynamic node labels and relationship types can prevent Cypher injection (a type of security vulnerability where an attacker injects malicious code into Cypher queries, potentially allowing unauthorized access or manipulation of a database). +For more information, see link:https://neo4j.com/developer/kb/protecting-against-cypher-injection/[Neo4j Knowledge Base -> Protecting against Cypher injection]. + +.Parameters +[source, parameters] +---- +{ + "nodeLabels": ["Person", "Director"], + "relType": "DIRECTED", + "movies": ["Ladybird", "Little Women", "Barbie"] +} +---- + +.Merge nodes and relationships using dynamic node labels and relationship types +[source, cypher] +---- +MERGE (greta:$($nodeLabels) {name: 'Greta Gerwig'}) +WITH greta +UNWIND $movies AS movieTitle +MERGE (greta)-[:$($relType)]->(m:Movie {title: movieTitle}) +RETURN greta.name AS name, labels(greta) AS gretaLabels, collect(m.title) AS moviesDirected +---- + +.Result +[role="queryresult",options="footer",cols="3* date('2024-10-25') TO regu |=== +=== New features + +[cols="2", options="header"] +|=== +| Feature +| Details + +a| +label:functionality[] +label:new[] +[source, cypher, role="noheader"] +---- +MATCH (movie:$($label)) +---- + +[source, cypher, role="noheader"] +---- +CREATE (movie:$($label)) +---- + +[source, cypher, role="noheader"] +---- +MERGE (movie:$($label)) +---- + +[source, cypher, role="noheader"] +---- +LOAD CSV WITH HEADERS FROM 'file:///artists-with-headers.csv' AS line +CREATE (n:$(line.label) {name: line.Name}) +---- + +| Added the ability reference node labels and relationship types in xref:clauses/match.adoc#dynamic-match[`MATCH`], xref:clauses/create.adoc#dynamic-create[`CREATE`], and xref:clauses/merge.adoc#dynamic-merge[`MERGE`] clauses. +Also introduced the ability to specify CSV columns dynamically when using xref:clauses/load-csv.adoc#dynamic-load[`LOAD CSV`]. +|=== + +For more information, see: + +* xref:clauses/set.adoc#dynamic-set-property[Dynamically `SET` or updating a property] and xref:clauses/set.adoc#dynamic-set-node-label[Dynamically `SET` a node label] +* xref:clauses/remove.adoc#dynamic-remove-property[Dynamically `REMOVE` a property] and xref:clauses/remove.adoc#dynamic-remove-node-label[Dynamically `REMOVE` a node label] +* * xref:clauses/match.adoc#dynamic-match[`MATCH` nodes and relationships using dynamic node labels and relationship types] +* xref:clauses/create.adoc#dynamic-create[`CREATE` nodes and relationships using dynamic node labels and relationship types] +* xref:clauses/merge.adoc#dynamic-merge[`MERGE` nodes and relationships using dynamic node labels and relationship types] + [[cypher-deprecations-additions-removals-5.25]] == Neo4j 5.25 @@ -208,7 +251,7 @@ label:new[] SET n[$prop] = "hello world" REMOVE n[$prop] ---- -| Added the ability to dynamically reference properties in xref:clauses/set.adoc#set-dynamically-a-property[SET] and xref:clauses/remove.adoc#remove-remove-a-property-dynamically[REMOVE] clauses. +| Added the ability to dynamically reference properties in xref:clauses/set.adoc#dynamic-set-property[SET] and xref:clauses/remove.adoc#dynamic-remove-property[REMOVE] clauses. a| label:functionality[] From fa246625b42f30a036582073cf0a4f9f68ffb481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Tue, 5 Nov 2024 10:05:00 +0100 Subject: [PATCH 04/17] more --- modules/ROOT/pages/clauses/create.adoc | 13 ------------- modules/ROOT/pages/clauses/match.adoc | 8 -------- modules/ROOT/pages/clauses/merge.adoc | 7 ------- modules/ROOT/pages/clauses/remove.adoc | 7 ++++--- modules/ROOT/pages/clauses/set.adoc | 4 ++-- 5 files changed, 6 insertions(+), 33 deletions(-) diff --git a/modules/ROOT/pages/clauses/create.adoc b/modules/ROOT/pages/clauses/create.adoc index 3038b2243..41602bb5f 100644 --- a/modules/ROOT/pages/clauses/create.adoc +++ b/modules/ROOT/pages/clauses/create.adoc @@ -220,10 +220,6 @@ CREATE ()-[r:$()]->() The expression must evaluate to a `STRING NOT NULL | LIST NOT NULL` value. -[NOTE] -Using dynamic node labels and relationship types can prevent Cypher injection (a type of security vulnerability where an attacker injects malicious code into Cypher queries, potentially allowing unauthorized access or manipulation of a database). -For more information, see link:https://neo4j.com/developer/kb/protecting-against-cypher-injection/[Neo4j Knowledge Base -> Protecting against Cypher injection]. - .Parameters [source, parameters] ---- @@ -260,15 +256,6 @@ Properties set: 4 + Labels added: 5 |=== -For more information, see: - -* xref:clauses/set.adoc#dynamic-set-property[Dynamically `SET` or updating a property] and xref:clauses/set.adoc#dynamic-set-node-label[Dynamically `SET` a node label] -* xref:clauses/remove.adoc#dynamic-remove-property[Dynamically `REMOVE` a property] and xref:clauses/remove.adoc#dynamic-remove-node-label[Dynamically `REMOVE` a node label] -* xref:clauses/match.adoc#dynamic-match[`MATCH` nodes and relationships using dynamic node labels and relationship types] -* xref:clauses/merge.adoc#dynamic-merge[`MERGE` nodes and relationships using dynamic node labels and relationship types] -* xref:clauses/load-csv.adoc#dynamic-columns[Import CSV using dynamic columns] - - [role=label--new-5.18] [[insert-as-synonym-of-create]] == `INSERT` as a synonym of `CREATE` diff --git a/modules/ROOT/pages/clauses/match.adoc b/modules/ROOT/pages/clauses/match.adoc index 5eb4a4d90..f313ffbe1 100644 --- a/modules/ROOT/pages/clauses/match.adoc +++ b/modules/ROOT/pages/clauses/match.adoc @@ -626,11 +626,3 @@ RETURN relationshipType, count(r) AS relationshipCount 2+d|Rows: 2 |=== - -For more information, see: - -* xref:clauses/set.adoc#dynamic-set-property[Dynamically `SET` or updating a property] and xref:clauses/set.adoc#dynamic-set-node-label[Dynamically `SET` a node label] -* xref:clauses/remove.adoc#dynamic-remove-property[Dynamically `REMOVE` a property] and xref:clauses/remove.adoc#dynamic-remove-node-label[Dynamically `REMOVE` a node label] -* xref:clauses/create.adoc#dynamic-create[`CREATE` nodes and relationships using dynamic node labels and relationship types] -* xref:clauses/merge.adoc#dynamic-merge[`MERGE` nodes and relationships using dynamic node labels and relationship types] -* xref:clauses/load-csv.adoc#dynamic-columns[Import CSV using dynamic columns] \ No newline at end of file diff --git a/modules/ROOT/pages/clauses/merge.adoc b/modules/ROOT/pages/clauses/merge.adoc index c60873809..bd143ac44 100644 --- a/modules/ROOT/pages/clauses/merge.adoc +++ b/modules/ROOT/pages/clauses/merge.adoc @@ -739,10 +739,3 @@ Properties set: 4 + Labels added: 5 |=== -For more information, see: - -* xref:clauses/set.adoc#dynamic-set-property[Dynamically `SET` or updating a property] and xref:clauses/set.adoc#dynamic-set-node-label[Dynamically `SET` a node label] -* xref:clauses/remove.adoc#dynamic-remove-property[Dynamically `REMOVE` a property] and xref:clauses/remove.adoc#dynamic-remove-node-label[Dynamically `REMOVE` a node label] -* xref:clauses/match.adoc#dynamic-match[`MATCH` nodes and relationships using dynamic node labels and relationship types] -* xref:clauses/create.adoc#dynamic-create[`CREATE` nodes and relationships using dynamic node labels and relationship types] -* xref:clauses/load-csv.adoc#dynamic-columns[Import CSV using dynamic columns] diff --git a/modules/ROOT/pages/clauses/remove.adoc b/modules/ROOT/pages/clauses/remove.adoc index 7d72f638b..62962a3af 100644 --- a/modules/ROOT/pages/clauses/remove.adoc +++ b/modules/ROOT/pages/clauses/remove.adoc @@ -70,7 +70,7 @@ Instead, using xref::clauses/set.adoc#set-remove-properties-using-empty-map[`SET [role=label--new-5.24] [[dynamic-remove-property]] -== Dynamically removing a property +== Dynamically REMOVE a property `REMOVE` can be used to remove a property on a node or relationship even when the property key name is not statically known. @@ -82,7 +82,6 @@ REMOVE n[key] The dynamically calculated key must evaluate to a `STRING` value. This query creates a copy of every property on the nodes: - .Query [source, cypher, indent=0] ---- @@ -132,7 +131,7 @@ Labels removed: 1 [role=label--new-5.24] [[dynamic-remove-node-label]] -== Dynamically removing a node label +== Dynamically REMOVE a node label `REMOVE` can be used to remove a label on a node even when the label is not statically known. @@ -142,6 +141,8 @@ MATCH (n) REMOVE n:$(expr) ---- +The expression must evaluate to a `STRING NOT NULL | LIST NOT NULL` value. + .Query [source, cypher, indent=0] ---- diff --git a/modules/ROOT/pages/clauses/set.adoc b/modules/ROOT/pages/clauses/set.adoc index f6b96757e..d9b136599 100644 --- a/modules/ROOT/pages/clauses/set.adoc +++ b/modules/ROOT/pages/clauses/set.adoc @@ -163,7 +163,7 @@ Properties set: 1 [role=label--new-5.24] [[dynamic-set-property]] -== Dynamically setting or updating a property +== Dynamically SET or update a property `SET` can be used to set or update a property on a node or relationship even when the property key name is not statically known. @@ -542,7 +542,7 @@ Labels added: 1 [role=label--new-5.24] [[dynamic-set-node-label]] -== Dynamically setting a label +== Dynamically SET a node label `SET` can be used to set a label on a node even when the label is not statically known. From 5131a8de7ee23adc3ea89f259092a2f39d6966e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Tue, 5 Nov 2024 10:15:57 +0100 Subject: [PATCH 05/17] fix --- modules/ROOT/pages/clauses/load-csv.adoc | 14 +++++++------- modules/ROOT/pages/clauses/match.adoc | 4 ---- modules/ROOT/pages/clauses/merge.adoc | 4 ---- 3 files changed, 7 insertions(+), 15 deletions(-) diff --git a/modules/ROOT/pages/clauses/load-csv.adoc b/modules/ROOT/pages/clauses/load-csv.adoc index 49fbc7166..eb0cbba6b 100644 --- a/modules/ROOT/pages/clauses/load-csv.adoc +++ b/modules/ROOT/pages/clauses/load-csv.adoc @@ -301,7 +301,7 @@ Added 4 nodes, Set 8 properties, Added 4 labels [role=label--new-5.26] [[dynamic-columns]] -== Import CSV using dynamic columns +=== Import CSV using dynamic columns CSV columns can be referenced dynamically to map labels to nodes in the graph. This enables flexible data handling, allowing labels to be be populated from CSV column values without manually specifying each entry. @@ -324,16 +324,16 @@ RETURN n AS bandNodes ---- .Result -[role="queryresult",options="header,footer",cols="2*))]->() The expression must evaluate to a `STRING NOT NULL | LIST NOT NULL` value. -[NOTE] -Using dynamic node labels and relationship types can prevent Cypher injection (a type of security vulnerability where an attacker injects malicious code into Cypher queries, potentially allowing unauthorized access or manipulation of a database). -For more information, see link:https://neo4j.com/developer/kb/protecting-against-cypher-injection/[Neo4j Knowledge Base -> Protecting against Cypher injection]. - .Match labels dynamically using the `all()` function [source, cypher] ---- diff --git a/modules/ROOT/pages/clauses/merge.adoc b/modules/ROOT/pages/clauses/merge.adoc index bd143ac44..bafc3d2e7 100644 --- a/modules/ROOT/pages/clauses/merge.adoc +++ b/modules/ROOT/pages/clauses/merge.adoc @@ -699,10 +699,6 @@ MERGE ()-[r:$()]->() The expression must evaluate to a `STRING NOT NULL | LIST NOT NULL` value. -[NOTE] -Using dynamic node labels and relationship types can prevent Cypher injection (a type of security vulnerability where an attacker injects malicious code into Cypher queries, potentially allowing unauthorized access or manipulation of a database). -For more information, see link:https://neo4j.com/developer/kb/protecting-against-cypher-injection/[Neo4j Knowledge Base -> Protecting against Cypher injection]. - .Parameters [source, parameters] ---- From cfc3da486170d18f419ce22905c157527e24029d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Tue, 5 Nov 2024 10:32:39 +0100 Subject: [PATCH 06/17] more --- modules/ROOT/pages/clauses/load-csv.adoc | 2 +- modules/ROOT/pages/clauses/remove.adoc | 4 ++-- modules/ROOT/pages/clauses/set.adoc | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/ROOT/pages/clauses/load-csv.adoc b/modules/ROOT/pages/clauses/load-csv.adoc index eb0cbba6b..48e4bd138 100644 --- a/modules/ROOT/pages/clauses/load-csv.adoc +++ b/modules/ROOT/pages/clauses/load-csv.adoc @@ -301,7 +301,7 @@ Added 4 nodes, Set 8 properties, Added 4 labels [role=label--new-5.26] [[dynamic-columns]] -=== Import CSV using dynamic columns +=== Import CSV files using dynamic columns CSV columns can be referenced dynamically to map labels to nodes in the graph. This enables flexible data handling, allowing labels to be be populated from CSV column values without manually specifying each entry. diff --git a/modules/ROOT/pages/clauses/remove.adoc b/modules/ROOT/pages/clauses/remove.adoc index 62962a3af..2c7ab8291 100644 --- a/modules/ROOT/pages/clauses/remove.adoc +++ b/modules/ROOT/pages/clauses/remove.adoc @@ -70,7 +70,7 @@ Instead, using xref::clauses/set.adoc#set-remove-properties-using-empty-map[`SET [role=label--new-5.24] [[dynamic-remove-property]] -== Dynamically REMOVE a property +== Dynamically remove a property `REMOVE` can be used to remove a property on a node or relationship even when the property key name is not statically known. @@ -131,7 +131,7 @@ Labels removed: 1 [role=label--new-5.24] [[dynamic-remove-node-label]] -== Dynamically REMOVE a node label +== Dynamically remove a node label `REMOVE` can be used to remove a label on a node even when the label is not statically known. diff --git a/modules/ROOT/pages/clauses/set.adoc b/modules/ROOT/pages/clauses/set.adoc index d9b136599..4b2694bfb 100644 --- a/modules/ROOT/pages/clauses/set.adoc +++ b/modules/ROOT/pages/clauses/set.adoc @@ -163,7 +163,7 @@ Properties set: 1 [role=label--new-5.24] [[dynamic-set-property]] -== Dynamically SET or update a property +== Dynamically set or update a property `SET` can be used to set or update a property on a node or relationship even when the property key name is not statically known. @@ -542,7 +542,7 @@ Labels added: 1 [role=label--new-5.24] [[dynamic-set-node-label]] -== Dynamically SET a node label +== Dynamically set a node label `SET` can be used to set a label on a node even when the label is not statically known. From e3bd68402a007c62ee23c2cd2e496928ca174272 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Tue, 5 Nov 2024 10:36:53 +0100 Subject: [PATCH 07/17] fix additions --- .../deprecations-additions-removals-compatibility.adoc | 7 ------- 1 file changed, 7 deletions(-) diff --git a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc index 04ea01db8..fa36f388b 100644 --- a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc +++ b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc @@ -108,13 +108,6 @@ CREATE (n:$(line.label) {name: line.Name}) Also introduced the ability to specify CSV columns dynamically when using xref:clauses/load-csv.adoc#dynamic-load[`LOAD CSV`]. |=== -For more information, see: - -* xref:clauses/set.adoc#dynamic-set-property[Dynamically `SET` or updating a property] and xref:clauses/set.adoc#dynamic-set-node-label[Dynamically `SET` a node label] -* xref:clauses/remove.adoc#dynamic-remove-property[Dynamically `REMOVE` a property] and xref:clauses/remove.adoc#dynamic-remove-node-label[Dynamically `REMOVE` a node label] -* * xref:clauses/match.adoc#dynamic-match[`MATCH` nodes and relationships using dynamic node labels and relationship types] -* xref:clauses/create.adoc#dynamic-create[`CREATE` nodes and relationships using dynamic node labels and relationship types] -* xref:clauses/merge.adoc#dynamic-merge[`MERGE` nodes and relationships using dynamic node labels and relationship types] [[cypher-deprecations-additions-removals-5.25]] == Neo4j 5.25 From aef4d38002858f6111aeede85fe07e2e51889d93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Thu, 7 Nov 2024 13:24:49 +0100 Subject: [PATCH 08/17] post-review update --- modules/ROOT/pages/clauses/create.adoc | 4 +- modules/ROOT/pages/clauses/match.adoc | 73 ++++++++----------- modules/ROOT/pages/clauses/merge.adoc | 4 +- ...ions-additions-removals-compatibility.adoc | 11 ++- 4 files changed, 43 insertions(+), 49 deletions(-) diff --git a/modules/ROOT/pages/clauses/create.adoc b/modules/ROOT/pages/clauses/create.adoc index 41602bb5f..f5aeca7b1 100644 --- a/modules/ROOT/pages/clauses/create.adoc +++ b/modules/ROOT/pages/clauses/create.adoc @@ -209,7 +209,7 @@ Properties set: 4 [[dynamic-create]] == CREATE nodes and relationships using dynamic node labels and relationship types -Node labels and relationship types can be referenced dynamically in parameters and variables when creating nodes and relationships. +Node labels and relationship types can be referenced dynamically in expressions, parameters, and variables when creating nodes and relationships. .Syntax for creating nodes and relationships dynamically [source, syntax] @@ -219,6 +219,8 @@ CREATE ()-[r:$()]->() ---- The expression must evaluate to a `STRING NOT NULL | LIST NOT NULL` value. +Using a `LIST` with more than one item when creating a relationship using dynamic relationship types will fail. +This is because a relationship can only have exactly one type. .Parameters [source, parameters] diff --git a/modules/ROOT/pages/clauses/match.adoc b/modules/ROOT/pages/clauses/match.adoc index 87cc0dc35..511b7c4f1 100644 --- a/modules/ROOT/pages/clauses/match.adoc +++ b/modules/ROOT/pages/clauses/match.adoc @@ -17,11 +17,11 @@ 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'}), +CREATE (charlie:Person:Actor {name: 'Charlie Sheen'}), + (martin:Person:Actor {name: 'Martin Sheen'}), + (michael:Person:Actor {name: 'Michael Douglas'}), + (oliver:Person:Director {name: 'Oliver Stone'}), + (rob:Person:Director {name: 'Rob Reiner'}), (wallStreet:Movie {title: 'Wall Street'}), (charlie)-[:ACTED_IN {role: 'Bud Fox'}]->(wallStreet), (martin)-[:ACTED_IN {role: 'Carl Fox'}]->(wallStreet), @@ -494,7 +494,7 @@ For more information about how Cypher queries work, see xref:clauses/clause-comp [[dynamic-match]] == MATCH nodes and relationships using dynamic node labels and relationship types -Node labels and relationship types can be referenced dynamically in parameters and variables when matching nodes and relationships. +Node labels and relationship types can be referenced dynamically in expressions, parameters, and variables when matching nodes and relationships. .Syntax for matching node labels dynamically [source, syntax] @@ -504,6 +504,9 @@ MATCH (n:$any()) MATCH (n:$all()) ---- +[NOTE] +`MATCH (n:$all())` is functionally equivalent to `MATCH (n:$())`. + .Syntax for matching relationship types dynamically [source, syntax] ---- @@ -513,66 +516,50 @@ MATCH ()-[r:$all())]->() ---- The expression must evaluate to a `STRING NOT NULL | LIST NOT NULL` value. +If you use a `LIST` with more than one item in a relationship pattern with dynamic relationship types, no results will be returned. +This is because a relationship can only have exactly one type. -.Match labels dynamically using the `all()` function +.Match labels dynamically [source, cypher] ---- -WITH "Movie" AS label -MATCH (movie:$all(label)) -RETURN movie AS movieNodes +WITH ["Person", "Director"] AS labels +MATCH (directors:$(labels)) +RETURN directors ---- .Result [role="queryresult",options="header,footer",cols="1*` to an `all()` function evaluating a relationship pattern using dynamic relationship types, the list cannot contain more than one element. -This is because a relationship can only have exactly one type. - -.Attempting to match relationship patterns using more than one relationship type will not return any results -[source, cypher] ----- -MATCH ()-[r:$all(["ACTED_IN", "DIRECTED"])]->() -RETURN r ----- - -.Warning -[source, warning] ----- -Warning: The query contains a relationship type expression that cannot be satisfied. ----- - .Match nodes dynamically using the `any()` function [source, cypher] ---- -MATCH (n:$any(["Movie", "Person"]))-[:ACTED_IN|DIRECTED]->(m:Movie) -RETURN labels(n) AS labels, n.name AS person, collect(m.title) AS movies +MATCH (n:$any(["Movie", "Actor"])) +RETURN n as nodes ---- [NOTE] The xref:functions/predicate.adoc#functions-any[`any()`] function matches nodes that have any of the specified labels. .Result -[role="queryresult",options="header,footer",cols="3*() RETURN relationshipType, count(r) AS relationshipCount ---- diff --git a/modules/ROOT/pages/clauses/merge.adoc b/modules/ROOT/pages/clauses/merge.adoc index bafc3d2e7..c1928ce7b 100644 --- a/modules/ROOT/pages/clauses/merge.adoc +++ b/modules/ROOT/pages/clauses/merge.adoc @@ -688,7 +688,7 @@ RETURN person.name, person.bornIn, person.chauffeurName [[dynamic-merge]] == MERGE nodes and relationships using dynamic node labels and relationship types -Node labels and relationship types can be referenced dynamically in parameters and variables when merging nodes and relationships. +Node labels and relationship types can be referenced dynamically in expressions, parameters, and variables when merging nodes and relationships. .Syntax for merging nodes and relationships dynamically [source, syntax] @@ -698,6 +698,8 @@ MERGE ()-[r:$()]->() ---- The expression must evaluate to a `STRING NOT NULL | LIST NOT NULL` value. +Using a `LIST` with more than one item when merging a relationship using dynamic relationship types will fail. +This is because a relationship can only have exactly one type. .Parameters [source, parameters] diff --git a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc index fa36f388b..f86e023ce 100644 --- a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc +++ b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc @@ -85,17 +85,20 @@ label:functionality[] label:new[] [source, cypher, role="noheader"] ---- -MATCH (movie:$($label)) +MATCH (movie:$($label)), + ()-[r:$($type))]->() ---- [source, cypher, role="noheader"] ---- -CREATE (movie:$($label)) +CREATE (movie:$($label)), + ()-[r:$($type)]->() ---- [source, cypher, role="noheader"] ---- -MERGE (movie:$($label)) +MERGE (movie:$($label)), + ()-[r:$($type)]->() ---- [source, cypher, role="noheader"] @@ -104,7 +107,7 @@ LOAD CSV WITH HEADERS FROM 'file:///artists-with-headers.csv' AS line CREATE (n:$(line.label) {name: line.Name}) ---- -| Added the ability reference node labels and relationship types in xref:clauses/match.adoc#dynamic-match[`MATCH`], xref:clauses/create.adoc#dynamic-create[`CREATE`], and xref:clauses/merge.adoc#dynamic-merge[`MERGE`] clauses. +| Added the ability to dynamically reference node labels and relationship types in xref:clauses/match.adoc#dynamic-match[`MATCH`], xref:clauses/create.adoc#dynamic-create[`CREATE`], and xref:clauses/merge.adoc#dynamic-merge[`MERGE`] clauses. Also introduced the ability to specify CSV columns dynamically when using xref:clauses/load-csv.adoc#dynamic-load[`LOAD CSV`]. |=== From 2a3579ade8f20603d8bb97676312497a63909936 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Thu, 7 Nov 2024 13:30:35 +0100 Subject: [PATCH 09/17] update image --- modules/ROOT/images/graph_match_clause.svg | 2 +- modules/ROOT/pages/clauses/match.adoc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ROOT/images/graph_match_clause.svg b/modules/ROOT/images/graph_match_clause.svg index d2481798f..393b3fe23 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'DIRECTEDPersonname:'Oliver Stone'Movietitle:'Wall Street'Personname:'Michael Douglas'Personname:'Martin Sheen'Movietitle:'The American President'Personname:'Charlie Sheen'Personname:'Rob Reiner' +DIRECTEDACTED_INrole:'Gordon Gekko'ACTED_INrole:'Carl Fox'ACTED_INrole:'President Andrew Shepherd'ACTED_INrole:'A.J. MacInerney'ACTED_INrole:'Bud Fox'DIRECTEDPersonDirectorname:'Oliver Stone'Movietitle:'Wall Street'PersonActorname:'Michael Douglas'PersonActorname:'Martin Sheen'Movietitle:'The American President'PersonActorname:'Charlie Sheen'PersonDirectorname:'Rob Reiner' \ No newline at end of file diff --git a/modules/ROOT/pages/clauses/match.adoc b/modules/ROOT/pages/clauses/match.adoc index 511b7c4f1..b4cfcb7b8 100644 --- a/modules/ROOT/pages/clauses/match.adoc +++ b/modules/ROOT/pages/clauses/match.adoc @@ -542,7 +542,7 @@ RETURN directors [source, cypher] ---- MATCH (n:$any(["Movie", "Actor"])) -RETURN n as nodes +RETURN n AS nodes ---- [NOTE] From 270ff8191247d4688d525a0ee511f21c5491565a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Thu, 7 Nov 2024 13:37:44 +0100 Subject: [PATCH 10/17] fix additions --- .../deprecations-additions-removals-compatibility.adoc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc index f86e023ce..f025bb6a5 100644 --- a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc +++ b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc @@ -85,19 +85,19 @@ label:functionality[] label:new[] [source, cypher, role="noheader"] ---- -MATCH (movie:$($label)), +MATCH (n:$($label)), ()-[r:$($type))]->() ---- [source, cypher, role="noheader"] ---- -CREATE (movie:$($label)), +CREATE (n:$($label)), ()-[r:$($type)]->() ---- [source, cypher, role="noheader"] ---- -MERGE (movie:$($label)), +MERGE (n:$($label)), ()-[r:$($type)]->() ---- From b614ba27537d88c11d892df39e22d63d9dd5a40c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Tue, 12 Nov 2024 09:14:51 +0100 Subject: [PATCH 11/17] small fix --- .../pages/deprecations-additions-removals-compatibility.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc index f025bb6a5..cdca4c236 100644 --- a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc +++ b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc @@ -91,13 +91,13 @@ MATCH (n:$($label)), [source, cypher, role="noheader"] ---- -CREATE (n:$($label)), +CREATE (n:$($label)) ()-[r:$($type)]->() ---- [source, cypher, role="noheader"] ---- -MERGE (n:$($label)), +MERGE (n:$($label)) ()-[r:$($type)]->() ---- From 007d4887ffabc3ba04565d89cfe1c4dddae8cad5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Tue, 12 Nov 2024 09:16:18 +0100 Subject: [PATCH 12/17] fix --- modules/ROOT/pages/clauses/create.adoc | 2 +- modules/ROOT/pages/clauses/merge.adoc | 2 +- .../pages/deprecations-additions-removals-compatibility.adoc | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/ROOT/pages/clauses/create.adoc b/modules/ROOT/pages/clauses/create.adoc index f5aeca7b1..c9a0c9c9a 100644 --- a/modules/ROOT/pages/clauses/create.adoc +++ b/modules/ROOT/pages/clauses/create.adoc @@ -214,7 +214,7 @@ Node labels and relationship types can be referenced dynamically in expressions, .Syntax for creating nodes and relationships dynamically [source, syntax] ---- -CREATE (n:$()), +CREATE (n:$()) CREATE ()-[r:$()]->() ---- diff --git a/modules/ROOT/pages/clauses/merge.adoc b/modules/ROOT/pages/clauses/merge.adoc index c1928ce7b..20414a3b3 100644 --- a/modules/ROOT/pages/clauses/merge.adoc +++ b/modules/ROOT/pages/clauses/merge.adoc @@ -693,7 +693,7 @@ Node labels and relationship types can be referenced dynamically in expressions, .Syntax for merging nodes and relationships dynamically [source, syntax] ---- -MERGE (n:$()), +MERGE (n:$()) MERGE ()-[r:$()]->() ---- diff --git a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc index cdca4c236..f025bb6a5 100644 --- a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc +++ b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc @@ -91,13 +91,13 @@ MATCH (n:$($label)), [source, cypher, role="noheader"] ---- -CREATE (n:$($label)) +CREATE (n:$($label)), ()-[r:$($type)]->() ---- [source, cypher, role="noheader"] ---- -MERGE (n:$($label)) +MERGE (n:$($label)), ()-[r:$($type)]->() ---- From ed4ff85cf68bf0ccf299c06ae69061f7f44bf59c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Thu, 14 Nov 2024 15:24:21 +0100 Subject: [PATCH 13/17] query fix attempt --- modules/ROOT/pages/clauses/create.adoc | 16 ++++++---------- modules/ROOT/pages/clauses/match.adoc | 6 ++++-- modules/ROOT/pages/clauses/merge.adoc | 11 ++++------- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/modules/ROOT/pages/clauses/create.adoc b/modules/ROOT/pages/clauses/create.adoc index c9a0c9c9a..6104b0405 100644 --- a/modules/ROOT/pages/clauses/create.adoc +++ b/modules/ROOT/pages/clauses/create.adoc @@ -238,24 +238,20 @@ This is because a relationship can only have exactly one type. CREATE (greta:$($nodeLabels) {name: 'Greta Gerwig'}) WITH greta UNWIND $movies AS movieTitle -CREATE (greta)-[:$($relType)]->(m:Movie {title: movieTitle}) -RETURN greta.name AS name, labels(greta) AS gretaLabels, collect(m.title) AS moviesDirected +CREATE (greta)-[rel:$($relType)]->(m:Movie {title: movieTitle}) +RETURN greta.name AS name, labels(greta) AS labels, type(r) AS relType, collect(m.title) AS movies ---- .Result -[role="queryresult",options="footer",cols="3* Label expressions]. diff --git a/modules/ROOT/pages/clauses/merge.adoc b/modules/ROOT/pages/clauses/merge.adoc index 20414a3b3..36bafd39c 100644 --- a/modules/ROOT/pages/clauses/merge.adoc +++ b/modules/ROOT/pages/clauses/merge.adoc @@ -718,22 +718,19 @@ MERGE (greta:$($nodeLabels) {name: 'Greta Gerwig'}) WITH greta UNWIND $movies AS movieTitle MERGE (greta)-[:$($relType)]->(m:Movie {title: movieTitle}) -RETURN greta.name AS name, labels(greta) AS gretaLabels, collect(m.title) AS moviesDirected +RETURN greta.name AS name, labels(greta) AS labels, type(r) AS relType, collect(m.title) AS movies ---- .Result [role="queryresult",options="footer",cols="3* Date: Thu, 14 Nov 2024 15:32:50 +0100 Subject: [PATCH 14/17] oops --- modules/ROOT/pages/clauses/create.adoc | 2 +- modules/ROOT/pages/clauses/merge.adoc | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/ROOT/pages/clauses/create.adoc b/modules/ROOT/pages/clauses/create.adoc index 6104b0405..ee3df4e70 100644 --- a/modules/ROOT/pages/clauses/create.adoc +++ b/modules/ROOT/pages/clauses/create.adoc @@ -239,7 +239,7 @@ CREATE (greta:$($nodeLabels) {name: 'Greta Gerwig'}) WITH greta UNWIND $movies AS movieTitle CREATE (greta)-[rel:$($relType)]->(m:Movie {title: movieTitle}) -RETURN greta.name AS name, labels(greta) AS labels, type(r) AS relType, collect(m.title) AS movies +RETURN greta.name AS name, labels(greta) AS labels, type(rel) AS relType, collect(m.title) AS movies ---- .Result diff --git a/modules/ROOT/pages/clauses/merge.adoc b/modules/ROOT/pages/clauses/merge.adoc index 36bafd39c..37053b3c3 100644 --- a/modules/ROOT/pages/clauses/merge.adoc +++ b/modules/ROOT/pages/clauses/merge.adoc @@ -717,8 +717,8 @@ This is because a relationship can only have exactly one type. MERGE (greta:$($nodeLabels) {name: 'Greta Gerwig'}) WITH greta UNWIND $movies AS movieTitle -MERGE (greta)-[:$($relType)]->(m:Movie {title: movieTitle}) -RETURN greta.name AS name, labels(greta) AS labels, type(r) AS relType, collect(m.title) AS movies +MERGE (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 ---- .Result From d7a126a57319038e46f46e9ba3bd4cd2bb1dd100 Mon Sep 17 00:00:00 2001 From: Stefano Ottolenghi Date: Thu, 14 Nov 2024 15:50:25 +0000 Subject: [PATCH 15/17] fix tests --- modules/ROOT/pages/clauses/create.adoc | 4 ++-- modules/ROOT/pages/clauses/merge.adoc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/ROOT/pages/clauses/create.adoc b/modules/ROOT/pages/clauses/create.adoc index ee3df4e70..7a8c7c7ba 100644 --- a/modules/ROOT/pages/clauses/create.adoc +++ b/modules/ROOT/pages/clauses/create.adoc @@ -248,7 +248,7 @@ RETURN greta.name AS name, labels(greta) AS labels, type(rel) AS relType, collec | name | labels | relType | movies | "Greta Gerwig" -| ["Person, "Director"] +| ["Person", "Director"] | "DIRECTED" | ["Ladybird", "Little Women", "Barbie"] 4+d|Rows: 1 + @@ -257,7 +257,7 @@ RETURN greta.name AS name, labels(greta) AS labels, type(rel) AS relType, collec [role=label--new-5.18] [[insert-as-synonym-of-create]] == `INSERT` as a synonym of `CREATE` - + `INSERT` can be used as a synonym to `CREATE` for creating nodes and relationships, and was introduced as part of Cypher's xref:appendix/gql-conformance/index.adoc[]. However, `INSERT` requires that multiple labels are separated by an ampersand `&` and not by colon `:`. diff --git a/modules/ROOT/pages/clauses/merge.adoc b/modules/ROOT/pages/clauses/merge.adoc index 37053b3c3..67842158e 100644 --- a/modules/ROOT/pages/clauses/merge.adoc +++ b/modules/ROOT/pages/clauses/merge.adoc @@ -727,7 +727,7 @@ RETURN greta.name AS name, labels(greta) AS labels, type(rel) AS relType, collec | name | labels | relType | movies | "Greta Gerwig" -| ["Person, "Director"] +| ["Person", "Director"] | "DIRECTED" | ["Ladybird", "Little Women", "Barbie"] From 6912c0d270a216881e52bcbe93416f0ee2444eb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Fri, 15 Nov 2024 15:30:44 +0100 Subject: [PATCH 16/17] add information --- .../gql-conformance/additional-cypher.adoc | 87 +++++++++++++++++++ modules/ROOT/pages/clauses/create.adoc | 2 + modules/ROOT/pages/clauses/load-csv.adoc | 5 +- modules/ROOT/pages/clauses/match.adoc | 2 + modules/ROOT/pages/clauses/merge.adoc | 2 + modules/ROOT/pages/clauses/remove.adoc | 2 + modules/ROOT/pages/clauses/set.adoc | 6 +- 7 files changed, 103 insertions(+), 3 deletions(-) diff --git a/modules/ROOT/pages/appendix/gql-conformance/additional-cypher.adoc b/modules/ROOT/pages/appendix/gql-conformance/additional-cypher.adoc index 46134dceb..837a32330 100644 --- a/modules/ROOT/pages/appendix/gql-conformance/additional-cypher.adoc +++ b/modules/ROOT/pages/appendix/gql-conformance/additional-cypher.adoc @@ -78,6 +78,93 @@ Either the pattern already exists, or it needs to be created. | Syntactic construct for creating a `LIST` based on matchings of a pattern. |=== +[[dynamic-queries]] +== Dynamic queries + +Node labels, relationship types, properties, and CSV columns can be referenced dynamically using Cypher. +This allows for more flexible queries and mitigates the risk of Cypher injection. +(For more information about Cypher injection, see link:https://neo4j.com/developer/kb/protecting-against-cypher-injection/[Neo4j Knowledge Base -> Protecting against Cypher injection]). + +[options="header", cols="2a,5a"] +|=== +| Cypher feature +| Description + +a| +[source, cypher, role="noheader"] +---- +MATCH (n:$($label)), + ()-[r:$($type))]->() +---- + +| xref:clauses/match.adoc#dynamic-match[`MATCH` nodes and relationships using dynamic node labels and relationship types] + +a| +[source, cypher, role="noheader"] +---- +CREATE (n:$($label)), + ()-[r:$($type)]->() +---- + +| xref:clauses/create.adoc#dynamic-create[`CREATE` nodes and relationships using dynamic node labels and relationship types] + +a| +[source, cypher, role="noheader"] +---- +MERGE (n:$($label)), + ()-[r:$($type)]->() +---- + +| xref:clauses/merge.adoc#dynamic-merge[`MERGE` nodes and relationships using dynamic node labels and relationship types] + +a| +[source, cypher, role="noheader"] +---- +LOAD CSV WITH HEADERS FROM 'file:///artists-with-headers.csv' AS line +CREATE (n:$(line.label) {name: line.Name}) +---- + +| xref:clauses/load-csv.adoc#dynamic-columns[Import CSV files using dynamic columns] + + +a| +[source, cypher, role="noheader"] +---- +MATCH (n) +SET n[$key] = value +---- + +| xref:clauses/set.adoc#dynamic-set-property[Dynamically `SET` or update a property] + +a| +[source, cypher, role="noheader"] +---- +MATCH (n:Label) +SET n:$(n.property) +---- + +| xref:clauses/set.adoc#dynamic-set-node-label[Dynamically `SET` a node label] + +a| +[source, cypher, role="noheader"] +---- +MATCH (n {name: 'Peter'}) +REMOVE n:$($label) +---- + +| xref:clauses/remove.adoc#dynamic-remove-property[Dynamically `REMOVE` a property] + +a| +[source, cypher, role="noheader"] +---- +MATCH (n {name: 'Peter'}) +REMOVE n:$($label) +---- + +| xref:clauses/remove.adoc#dynamic-remove-node-label[Dynamically `REMOVE` a node label] + +|=== + [[functions]] == Functions diff --git a/modules/ROOT/pages/clauses/create.adoc b/modules/ROOT/pages/clauses/create.adoc index ee3df4e70..f3a40b4aa 100644 --- a/modules/ROOT/pages/clauses/create.adoc +++ b/modules/ROOT/pages/clauses/create.adoc @@ -210,6 +210,8 @@ Properties set: 4 == CREATE nodes and relationships using dynamic node labels and relationship types Node labels and relationship types can be referenced dynamically in expressions, parameters, and variables when creating nodes and relationships. +This allows for more flexible queries and mitigates the risk of Cypher injection. +(For more information about Cypher injection, see link:https://neo4j.com/developer/kb/protecting-against-cypher-injection/[Neo4j Knowledge Base -> Protecting against Cypher injection]). .Syntax for creating nodes and relationships dynamically [source, syntax] diff --git a/modules/ROOT/pages/clauses/load-csv.adoc b/modules/ROOT/pages/clauses/load-csv.adoc index 48e4bd138..0f8f30b8e 100644 --- a/modules/ROOT/pages/clauses/load-csv.adoc +++ b/modules/ROOT/pages/clauses/load-csv.adoc @@ -303,7 +303,10 @@ Added 4 nodes, Set 8 properties, Added 4 labels [[dynamic-columns]] === Import CSV files using dynamic columns -CSV columns can be referenced dynamically to map labels to nodes in the graph. This enables flexible data handling, allowing labels to be be populated from CSV column values without manually specifying each entry. +CSV columns can be referenced dynamically to map labels to nodes in the graph. +This enables flexible data handling, allowing labels to be be populated from CSV column values without manually specifying each entry. +It also mitigates the risk of Cypher injection. +(For more information about Cypher injection, see link:https://neo4j.com/developer/kb/protecting-against-cypher-injection/[Neo4j Knowledge Base -> Protecting against Cypher injection]). .bands-with-headers.csv [source, csv, filename="artists-with-headers.csv"] diff --git a/modules/ROOT/pages/clauses/match.adoc b/modules/ROOT/pages/clauses/match.adoc index b4e1a85ec..3efb1b979 100644 --- a/modules/ROOT/pages/clauses/match.adoc +++ b/modules/ROOT/pages/clauses/match.adoc @@ -497,6 +497,8 @@ For more information about how Cypher queries work, see xref:clauses/clause-comp == MATCH nodes and relationships using dynamic node labels and relationship types Node labels and relationship types can be referenced dynamically in expressions, parameters, and variables when matching nodes and relationships. +This allows for more flexible queries and mitigates the risk of Cypher injection. +(For more information about Cypher injection, see link:https://neo4j.com/developer/kb/protecting-against-cypher-injection/[Neo4j Knowledge Base -> Protecting against Cypher injection]). .Syntax for matching node labels dynamically [source, syntax] diff --git a/modules/ROOT/pages/clauses/merge.adoc b/modules/ROOT/pages/clauses/merge.adoc index 37053b3c3..2560caaae 100644 --- a/modules/ROOT/pages/clauses/merge.adoc +++ b/modules/ROOT/pages/clauses/merge.adoc @@ -689,6 +689,8 @@ RETURN person.name, person.bornIn, person.chauffeurName == MERGE nodes and relationships using dynamic node labels and relationship types Node labels and relationship types can be referenced dynamically in expressions, parameters, and variables when merging nodes and relationships. +This allows for more flexible queries and mitigates the risk of Cypher injection. +(For more information about Cypher injection, see link:https://neo4j.com/developer/kb/protecting-against-cypher-injection/[Neo4j Knowledge Base -> Protecting against Cypher injection]). .Syntax for merging nodes and relationships dynamically [source, syntax] diff --git a/modules/ROOT/pages/clauses/remove.adoc b/modules/ROOT/pages/clauses/remove.adoc index 2c7ab8291..ec5a887d6 100644 --- a/modules/ROOT/pages/clauses/remove.adoc +++ b/modules/ROOT/pages/clauses/remove.adoc @@ -73,6 +73,8 @@ Instead, using xref::clauses/set.adoc#set-remove-properties-using-empty-map[`SET == Dynamically remove a property `REMOVE` can be used to remove a property on a node or relationship even when the property key name is not statically known. +This allows for more flexible queries and mitigates the risk of Cypher injection. +(For more information about Cypher injection, see link:https://neo4j.com/developer/kb/protecting-against-cypher-injection/[Neo4j Knowledge Base -> Protecting against Cypher injection]). [source, syntax] ---- diff --git a/modules/ROOT/pages/clauses/set.adoc b/modules/ROOT/pages/clauses/set.adoc index 4b2694bfb..d90a891d1 100644 --- a/modules/ROOT/pages/clauses/set.adoc +++ b/modules/ROOT/pages/clauses/set.adoc @@ -166,6 +166,8 @@ Properties set: 1 == Dynamically set or update a property `SET` can be used to set or update a property on a node or relationship even when the property key name is not statically known. +This allows for more flexible queries and mitigates the risk of Cypher injection. +(For more information about Cypher injection, see link:https://neo4j.com/developer/kb/protecting-against-cypher-injection/[Neo4j Knowledge Base -> Protecting against Cypher injection]). [source, syntax] ---- @@ -549,7 +551,7 @@ Labels added: 1 [source, syntax] ---- MATCH (n) -SET n:$(expr) +SET n:$() ---- .Query @@ -629,7 +631,7 @@ Labels added: 2 |=== [role=label--new-5.24] -[[set-set-multiple-dynamic-labels-on-a-node]] +[[dynamic-set-multiple-node-labels]] == Set multiple labels dynamically on a node It is possible to set multiple labels dynamically using a `LIST` and/or by chaining them separately with a `:`: From a2211f0f1228e4b8184f01545f82ddeb95e39251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Tue, 19 Nov 2024 14:36:46 +0100 Subject: [PATCH 17/17] add performance note and fix long headers --- modules/ROOT/pages/clauses/create.adoc | 2 +- modules/ROOT/pages/clauses/match.adoc | 10 ++++++---- modules/ROOT/pages/clauses/merge.adoc | 6 +++++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/modules/ROOT/pages/clauses/create.adoc b/modules/ROOT/pages/clauses/create.adoc index 4e0dedc80..f2ee2cd58 100644 --- a/modules/ROOT/pages/clauses/create.adoc +++ b/modules/ROOT/pages/clauses/create.adoc @@ -207,7 +207,7 @@ Properties set: 4 [role=label--new-5.26] [[dynamic-create]] -== CREATE nodes and relationships using dynamic node labels and relationship types +== CREATE using dynamic node labels and relationship types Node labels and relationship types can be referenced dynamically in expressions, parameters, and variables when creating nodes and relationships. This allows for more flexible queries and mitigates the risk of Cypher injection. diff --git a/modules/ROOT/pages/clauses/match.adoc b/modules/ROOT/pages/clauses/match.adoc index 3efb1b979..3e56b8a13 100644 --- a/modules/ROOT/pages/clauses/match.adoc +++ b/modules/ROOT/pages/clauses/match.adoc @@ -494,7 +494,7 @@ For more information about how Cypher queries work, see xref:clauses/clause-comp [role=label--new-5.26] [[dynamic-match]] -== MATCH nodes and relationships using dynamic node labels and relationship types +== MATCH using dynamic node labels and relationship types Node labels and relationship types can be referenced dynamically in expressions, parameters, and variables when matching nodes and relationships. This allows for more flexible queries and mitigates the risk of Cypher injection. @@ -523,6 +523,10 @@ The expression must evaluate to a `STRING NOT NULL | LIST NOT N If you use a `LIST` with more than one item in a relationship pattern with dynamic relationship types, no results will be returned. This is because a relationship can only have exactly one type. +[NOTE] +Queries using dynamic values may not be as performant as those using static values. +This is because the xref:planning-and-tuning/execution-plans.adoc[Cypher planner] uses statically available information when planning queries to determine whether to use an xref:indexes/search-performance-indexes/overview.adoc[index] or not, and this is not possible when using dynamic values. + .Match labels dynamically [source, cypher] ---- @@ -549,9 +553,6 @@ MATCH (n:$any(["Movie", "Actor"])) RETURN n AS nodes ---- -[NOTE] -The xref:functions/predicate.adoc#functions-any[`any()`] function matches nodes that have any of the specified labels. - .Result [role="queryresult",options="header,footer",cols="1* NOT N Using a `LIST` with more than one item when merging a relationship using dynamic relationship types will fail. This is because a relationship can only have exactly one type. +[NOTE] +Queries using dynamic values may not be as performant as those using static values. +This is because the xref:planning-and-tuning/execution-plans.adoc[Cypher planner] uses statically available information when planning queries to determine whether to use an xref:indexes/search-performance-indexes/overview.adoc[index] or not, and this is not possible when using dynamic values. + .Parameters [source, parameters] ----