From 96a733da7e456d0c251040d1976781227c3da83d Mon Sep 17 00:00:00 2001 From: Satia Herfert Date: Wed, 22 Mar 2023 10:58:41 +0100 Subject: [PATCH 1/9] Deprecate `connectComponentsPlanner` (#468) --- ...ions-additions-removals-compatibility.adoc | 28 +++++++++++++++++++ .../pages/query-tuning/query-options.adoc | 8 +++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc index af448eb3d..2fa0b7e43 100644 --- a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc +++ b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc @@ -10,6 +10,34 @@ New features are added to the language continuously, and occasionally, some feat This section lists all of the features that have been removed, deprecated, added, or extended in different Cypher versions. Replacement syntax for deprecated and removed features are also indicated. +[[cypher-deprecations-additions-removals-5.7]] +== Version 5.7 + +=== Deprecated features + +[cols="2", options="header"] +|=== +| Feature +| Details + +a| +label:functionality[] +label:deprecated[] +[source, cypher, role="noheader"] +---- +CYPHER connectComponentsPlanner=greedy MATCH (a), (b) RETURN * +---- + +[source, cypher, role="noheader"] +---- +CYPHER connectComponentsPlanner=idp MATCH (a), (b) RETURN * +---- +a| + +The Cypher query option `connectComponentsPlanner` is deprecated and will be removed without a replacement. +The product's default behavior of using a cost-based IDP search algorithm when combining sub-plans will be kept. +|=== + [[cypher-deprecations-additions-removals-5.6]] == Version 5.6 diff --git a/modules/ROOT/pages/query-tuning/query-options.adoc b/modules/ROOT/pages/query-tuning/query-options.adoc index 4c756d198..e075f4f41 100644 --- a/modules/ROOT/pages/query-tuning/query-options.adoc +++ b/modules/ROOT/pages/query-tuning/query-options.adoc @@ -84,7 +84,7 @@ Using this option can significantly _increase_ the planning time of the query. [[cypher-connect-components-planner]] -== Cypher connect-components planner +== Cypher connect-components planner label:deprecated[] One part of the Cypher planner is responsible for combining sub-plans for separate patterns into larger plans - a task referred to as _connecting components_. @@ -117,6 +117,12 @@ Using this option can significantly _increase_ the planning time of the query bu |=== +[IMPORTANT] +==== +The Cypher query option `connectComponentsPlanner` is deprecated and will be removed without a replacement. +The product's default behavior of using a cost-based IDP search algorithm when combining sub-plans will be kept. +==== + [[cypher-update-strategy]] == Cypher update strategy From ef2b80f619692435c0d2bbba16f946f3c4d44324 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Wed, 22 Mar 2023 10:17:55 +0100 Subject: [PATCH 2/9] update Neo4j version (#481) --- antora.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/antora.yml b/antora.yml index 02c5bc720..47c896cc7 100644 --- a/antora.yml +++ b/antora.yml @@ -7,5 +7,5 @@ nav: asciidoc: attributes: neo4j-version: '5' - neo4j-version-minor: '5.6' - neo4j-version-exact: '5.6.0' + neo4j-version-minor: '5.7' + neo4j-version-exact: '5.7.0' From e77e87b91baf2825d97e36cf46a943678eb1cb6a Mon Sep 17 00:00:00 2001 From: Hannes Sandberg Date: Fri, 24 Mar 2023 14:47:32 +0100 Subject: [PATCH 3/9] fix conflict --- .../ROOT/pages/administration/databases.adoc | 3 ++- ...ions-additions-removals-compatibility.adoc | 20 +++++++++++++++++++ modules/ROOT/pages/keyword-glossary.adoc | 2 +- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/modules/ROOT/pages/administration/databases.adoc b/modules/ROOT/pages/administration/databases.adoc index 41ad9a00e..5f26bcf04 100644 --- a/modules/ROOT/pages/administration/databases.adoc +++ b/modules/ROOT/pages/administration/databases.adoc @@ -93,6 +93,7 @@ ALTER DATABASE name [IF EXISTS] SET ACCESS {READ ONLY \| READ WRITE} \| SET TOPOLOGY n PRIMAR{Y\|IES} [m SECONDAR{Y\|IES}] } +[WAIT [n [SEC[OND[S]]]]\|NOWAIT] ---- | STOP DATABASE @@ -1125,7 +1126,7 @@ To ensure the database to be dropped is standard and not composite, the user fir [[administration-wait-nowait]] == Wait options -Aside from `SHOW DATABASES` and `ALTER DATABASE`, all database management commands accept an optional `WAIT`/`NOWAIT` clause. +Aside from `SHOW DATABASES`, all database management commands accept an optional `WAIT`/`NOWAIT` clause. The `WAIT`/`NOWAIT` clause allows you to specify a time limit in which the command must complete and return. The options are: diff --git a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc index 2fa0b7e43..f55d915a2 100644 --- a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc +++ b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc @@ -38,6 +38,26 @@ The Cypher query option `connectComponentsPlanner` is deprecated and will be rem The product's default behavior of using a cost-based IDP search algorithm when combining sub-plans will be kept. |=== + +=== Updated features + +[cols="2", options="header"] +|=== +| Feature +| Details + +a| +label:functionality[] +label:updated[] +[source, cypher, role="noheader"] +---- +ALTER DATABASE ... [WAIT [n [SEC[OND[S]]]]\|NOWAIT] +---- +a| +New sub-clause `WAIT` for `ALTER DATABASE`. +This enables adding a waiting clause to specify a time limit in which the command must be completed and returned. +|=== + [[cypher-deprecations-additions-removals-5.6]] == Version 5.6 diff --git a/modules/ROOT/pages/keyword-glossary.adoc b/modules/ROOT/pages/keyword-glossary.adoc index 2b43d610d..87aeb309b 100644 --- a/modules/ROOT/pages/keyword-glossary.adoc +++ b/modules/ROOT/pages/keyword-glossary.adoc @@ -1084,7 +1084,7 @@ The following commands are only executable against the `system` database: | User and role | Change the password of the user that is currently logged in. -| xref::administration/databases.adoc#administration-databases-alter-database[ALTER DATABASE ... [IF EXISTS\] [SET ACCESS {READ ONLY \| READ WRITE}\] [SET TOPOLOGY n PRIMAR{Y\|IES} [m SECONDAR{Y\|IES}\]\] [WAIT [n [SEC[OND[S\]\]\]\]\|NOWAIT\]] +| xref:databases.adoc#administration-databases-alter-database[ALTER DATABASE ... [IF EXISTS\] [SET ACCESS {READ ONLY \| READ WRITE}\] [SET TOPOLOGY n PRIMAR{Y\|IES} [m SECONDAR{Y\|IES}\]\] [WAIT [n [SEC[OND[S\]\]\]\]\|NOWAIT\]] | Database | Modifies the database access mode and / or topology. From 2559d7ecda74e69c26cc89a3e981746c056e9ae5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Cord=C3=B3n?= Date: Fri, 24 Mar 2023 14:00:33 +0000 Subject: [PATCH 4/9] Adds docs for status report and error behaviour in CALL IN TXs (#483) This was added initially and approved in #312 and reverted in #477 due to the branch dev from docs not having been repointed at neo4j 4.7 yet. This PR reverts the revert. --------- --- modules/ROOT/pages/clauses/call-subquery.adoc | 255 +++++++++++++++++- 1 file changed, 247 insertions(+), 8 deletions(-) diff --git a/modules/ROOT/pages/clauses/call-subquery.adoc b/modules/ROOT/pages/clauses/call-subquery.adoc index 1df778181..4dbbd751b 100644 --- a/modules/ROOT/pages/clauses/call-subquery.adoc +++ b/modules/ROOT/pages/clauses/call-subquery.adoc @@ -415,6 +415,11 @@ RETURN p.name, youngerPersonsCount Subqueries can be made to execute in separate, inner transactions, producing intermediate commits. This can come in handy when doing large write operations, like batch updates, imports, and deletes. To execute a subquery in separate transactions, you add the modifier `IN TRANSACTIONS` after the subquery. +An outer transaction is opened to report back the accumulated statistics for the inner transactions +(created and deleted nodes, relationships, etc) and it will succeed or fail depending on the results +of those inner transactions. +For more information, see <>. +Canceling that outer transaction will cancel the inner ones. The following example uses a CSV file and the `LOAD CSV` clause to import more data to the example graph. It creates nodes in separate transactions using `+CALL { ... } IN TRANSACTIONS+`: @@ -435,7 +440,7 @@ It creates nodes in separate transactions using `+CALL { ... } IN TRANSACTIONS+` LOAD CSV FROM 'file:///friends.csv' AS line CALL { WITH line - CREATE (:PERSON {name: line[1], age: toInteger(line[2])}) + CREATE (:Person {name: line[1], age: toInteger(line[2])}) } IN TRANSACTIONS ---- @@ -601,15 +606,20 @@ The batch size of `2 ROWS` is an example given the small data set used here. For larger data sets, you might want to use larger batch sizes, such as `10000 ROWS`. ==== +=== Error behaviour [[txs_error_behaviour]] +Users can choose one of three different option flags to control the behaviour +in case of an error occurring in any of the inner transactions of `+CALL { ... } IN TRANSACTIONS+`: -=== Errors - -If an error occurs in `+CALL { ... } IN TRANSACTIONS+` the entire query fails and -both the current inner transaction and the outer transaction are rolled back. +* `ON ERROR CONTINUE` to ignore a recoverable error and continue the execution of subsequent inner transactions. +The outer transaction succeeds. +It will cause the expected variables from the failed inner query to be bound as null for that specific transaction. +* `ON ERROR BREAK` to ignore a recoverable error and stop the execution of subsequent inner transactions. The outer transaction succeeds. +It will cause expected variables from the failed inner query to be bound as null for all onward transactions (including the failed one). +* `ON ERROR FAIL` to acknowledge a recoverable error and stop the execution of subsequent inner transactions. The outer transaction fails. This is the default behaviour if no flag is explicitly specified. [IMPORTANT] ==== -On error, any previously committed inner transactions remain committed, and are not rolled back. +On error, any previously committed inner transactions remain committed, and are not rolled back. Any failed inner transactions are rolled back. ==== In the following example, the last subquery execution in the second inner transaction fails @@ -621,7 +631,7 @@ due to division by zero. UNWIND [4, 2, 1, 0] AS i CALL { WITH i - CREATE (:Example {num: 100/i}) + CREATE (:Person {num: 100/i}) } IN TRANSACTIONS OF 2 ROWS RETURN i ---- @@ -637,7 +647,7 @@ When the failure occurred, the first transaction had already been committed, so .Query [source, cypher] ---- -MATCH (e:Example) +MATCH (e:Person) RETURN e.num ---- @@ -650,6 +660,235 @@ RETURN e.num 1+d|Rows: 2 |=== +In the following example, `ON ERROR CONTINUE` is used after a failed inner transaction to execute the remaining inner transactions and not fail the outer transaction: + +.Query +[source, cypher] +---- +UNWIND [1, 0, 2, 4] AS i +CALL { + WITH i + CREATE (n:Person {num: 100/i}) // Note, fails when i = 0 + RETURN n +} IN TRANSACTIONS + OF 1 ROW + ON ERROR CONTINUE +RETURN n.num; +---- + +.Result +[role="queryresult",options="header,footer",cols="1*>. + +After each execution of the inner query finishes (successfully or not), a status value is created that records information about the execution and the transaction that executed it: + +* If the inner execution produces one or more rows as output, then a binding to this status value is added to each row, under the selected variable name. +* If the inner execution fails then a single row is produced containing a binding to this status value under the selected variable, and null bindings for all variables that should have been returned by the inner query (if any). + +The status value is a map value with the following fields: + +* `started`: `true` when the inner transaction was started, `false` otherwise. +* `committed`, true when the inner transaction changes were successfully committed, false otherwise. +* `transactionId`: the inner transaction id, or null if the transaction was not started. +* `errorMessage`, the inner transaction error message, or null in case of no error. + +Example of reporting status with `ON ERROR CONTINUE`: + +.Query +[source, cypher, indent=0, role=test-result-skip] +---- +UNWIND [1, 0, 2, 4] AS i +CALL { + WITH i + CREATE (n:Person {num: 100/i}) // Note, fails when i = 0 + RETURN n +} IN TRANSACTIONS + OF 1 ROW + ON ERROR CONTINUE + REPORT STATUS AS s +RETURN n.num, s; +---- + +.Result +[role="queryresult",options="header,footer",cols="2* Date: Tue, 18 Apr 2023 08:45:25 +0200 Subject: [PATCH 5/9] Re-add relationship constraint documentation (#490) Companion PR to https://github.com/neo4j/docs-cheat-sheet/pull/69 --- modules/ROOT/pages/constraints/examples.adoc | 454 +++++++++--------- modules/ROOT/pages/constraints/index.adoc | 23 +- modules/ROOT/pages/constraints/syntax.adoc | 67 +-- ...ions-additions-removals-compatibility.adoc | 114 ++--- .../ROOT/pages/execution-plans/operators.adoc | 4 +- .../ROOT/pages/introduction/cypher_neo4j.adoc | 12 +- .../introduction/neo4j-databases-graphs.adoc | 12 +- modules/ROOT/pages/keyword-glossary.adoc | 18 +- 8 files changed, 288 insertions(+), 416 deletions(-) diff --git a/modules/ROOT/pages/constraints/examples.adoc b/modules/ROOT/pages/constraints/examples.adoc index 6fab58884..beaf0db61 100644 --- a/modules/ROOT/pages/constraints/examples.adoc +++ b/modules/ROOT/pages/constraints/examples.adoc @@ -47,13 +47,11 @@ FOR (book:Book) REQUIRE book.isbn IS UNIQUE Added 1 constraint. ---- -//// -TODO: Re-add this part when adding back relationship key and uniqueness constraints [NOTE] ==== -The statistics will be updated to say `Node uniqueness constraints` in Neo4j version 6.0. +The detailed statistics view currently says `Unique constraints added: 1`. +It will be updated to say `Node property uniqueness constraints added: 1` in Neo4j version 6.0. ==== -//// ====== @@ -62,7 +60,7 @@ The statistics will be updated to say `Node uniqueness constraints` in Neo4j ver [[constraints-create-a-node-uniqueness-constraint-if-not-exist]] === Handling existing constraints when creating a constraint -Creating an already existing constraint will fail. +Creating an already existing constraint will fail. To avoid such an error, `IF NOT EXISTS` can be added to the `CREATE` command. This will ensure that no error is thrown and no constraint is created if any other constraint with the given name or another node property uniqueness constraint on the same schema already exists. @@ -85,13 +83,11 @@ Assuming no constraint with the given name or other node property uniqueness con Added 1 constraint. ---- -//// -TODO: Re-add this part when adding back relationship key and uniqueness constraints [NOTE] ==== -The statistics will be updated to say `Node uniqueness constraints` in Neo4j version 6.0. +The detailed statistics view currently says `Unique constraints added: 1`. +It will be updated to say `Node property uniqueness constraints added: 1` in Neo4j version 6.0. ==== -//// ====== @@ -130,13 +126,11 @@ OPTIONS { Added 1 constraint. ---- -//// -TODO: Re-add this part when adding back relationship key and uniqueness constraints [NOTE] ==== -The statistics will be updated to say `Node uniqueness constraints` in Neo4j version 6.0. +The detailed statistics view currently says `Unique constraints added: 1`. +It will be updated to say `Node property uniqueness constraints added: 1` in Neo4j version 6.0. ==== -//// ====== @@ -175,13 +169,10 @@ Constraint already exists: Constraint( id=4, name='preExisting_book_published', type='UNIQUENESS', schema=(:Book {published}), ownedIndex=3 ) ---- -//// -TODO: Re-add this part when adding back relationship key and uniqueness constraints [NOTE] ==== -The constraint type will be updated to say `NODE_UNIQUENESS` in Neo4j version 6.0. +The constraint type will be updated to say `NODE PROPERTY UNIQUENESS` in Neo4j version 6.0. ==== -//// ====== @@ -307,13 +298,10 @@ Unable to create Constraint( name='book_title', type='UNIQUENESS', schema=(:Book Both Node(0) and Node(1) have the label `Book` and property `title` = 'Moby Dick' ---- -//// -TODO: Re-add this part when adding back relationship key and uniqueness constraints [NOTE] ==== -The constraint type will be updated to say `NODE_UNIQUENESS` in Neo4j version 6.0. +The constraint type will be updated to say `NODE PROPERTY UNIQUENESS` in Neo4j version 6.0. ==== -//// ====== @@ -331,9 +319,6 @@ WHERE book1.title = book2.title AND NOT book1 = book2 RETURN book1, book2 ---- -//// -TODO: Re-add this part when adding back relationship key and uniqueness constraints -TODO: Remove 'test-skip' message on queries when feature is introduced [[constraints-examples-relationship-uniqueness]] == Relationship property uniqueness constraints @@ -348,7 +333,6 @@ A relationship property uniqueness constraint ensures that all relationships wit * xref::constraints/examples.adoc#constraints-create-a-relationship-that-violates-a-uniqueness-constraint[] * xref::constraints/examples.adoc#constraints-fail-to-create-a-uniqueness-constraint-due-to-conflicting-relationships[] - [discrete] [[constraints-create-a-relationship-uniqueness-constraints]] === Create a relationship property uniqueness constraint @@ -360,21 +344,24 @@ When creating a property uniqueness constraint, a name can be provided. ====== .Query -[source, cypher, role=test-skip] +[source, cypher] ---- -CREATE CONSTRAINT constraint_name -FOR ()-[friend:FRIENDS_WITH]-() REQUIRE friend.nickname IS UNIQUE +CREATE CONSTRAINT sequels +FOR ()-[sequel:SEQUEL_OF]-() REQUIRE (sequel.order, sequel.seriesTitle) IS UNIQUE ---- .Result [queryresult] ---- -+-------------------+ -| No data returned. | -+-------------------+ -Relationship uniqueness constraints added: 1 +Added 1 constraint. ---- +[NOTE] +==== +The detailed statistics view currently says `Relationship uniqueness constraints added: 1`. +It will be updated to say `Relationship property uniqueness constraints added: 1` in Neo4j version 6.0. +==== + ====== @@ -391,23 +378,26 @@ This will ensure that no error is thrown and no constraint is created if any oth ====== .Query -[source, cypher, role=test-skip] +[source, cypher] ---- -CREATE CONSTRAINT constraint_name IF NOT EXISTS -FOR ()-[friend:FRIENDS_WITH]-() REQUIRE friend.nickname IS UNIQUE +CREATE CONSTRAINT sequels IF NOT EXISTS +FOR ()-[sequel:SEQUEL_OF]-() REQUIRE (sequel.order) IS UNIQUE ---- -Assuming no constraint with the given name or other relationship property uniqueness constraint on the same schema exists: +Assuming a constraint with the given name already exists: .Result [queryresult] ---- -+-------------------+ -| No data returned. | -+-------------------+ -Relationship uniqueness constraints added: 1 +(no changes, no records) ---- +[NOTE] +==== +The detailed statistics view currently says `Relationship uniqueness constraints added: 1`. +It will be updated to say `Relationship property uniqueness constraints added: 1` in Neo4j version 6.0. +==== + ====== @@ -430,24 +420,27 @@ The only valid value for the index provider is: ====== .Query -[source, cypher, role=test-skip] +[source, cypher] ---- -CREATE CONSTRAINT constraint_with_options -FOR ()-[friend:FRIENDS_WITH]-() REQUIRE (friend.nickname, friend.since) IS UNIQUE +CREATE CONSTRAINT rel_constraint_with_options +FOR ()-[sequel:SEQUEL_OF]-() REQUIRE (sequel.order, sequel.seriesTitle, sequel.number) IS UNIQUE OPTIONS { - indexProvider: 'range-1.0', + indexProvider: 'range-1.0' } ---- .Result [queryresult] ---- -+-------------------+ -| No data returned. | -+-------------------+ -Relationship uniqueness constraints added: 1 +Added 1 constraint. ---- +[NOTE] +==== +The detailed statistics view currently says `Relationship uniqueness constraints added: 1`. +It will be updated to say `Relationship property uniqueness constraints added: 1` in Neo4j version 6.0. +==== + ====== There are no valid index configuration values for the constraint-backing range indexes. @@ -461,15 +454,12 @@ There are no valid index configuration values for the constraint-backing range i .+CREATE CONSTRAINT+ ====== -Create a property uniqueness constraint on the property `nickname` on relationships with the `FRIENDS_WITH` relationship type, when that constraint already exists. - -// Set-up to get expected behavior: -// CREATE CONSTRAINT preExistingUnique FOR ()-[friend:FRIENDS_WITH]-() REQUIRE friend.nickname IS UNIQUE +Create a property uniqueness constraint on the properties `order` and `seriesTitle` on relationships with the `SEQUEL_OF` relationship type, when that constraint already exists. .Query -[source, cypher, role=test-skip] +[source, cypher, role=test-fail] ---- -CREATE CONSTRAINT FOR ()-[friend:FRIENDS_WITH]-() REQUIRE friend.nickname IS UNIQUE +CREATE CONSTRAINT sequel_order_seriestitle FOR ()-[sequel:SEQUEL_OF]-() REQUIRE (sequel.order, sequel.seriesTitle) IS UNIQUE ---- In this case, the constraint cannot be created because it already exists. @@ -478,9 +468,14 @@ In this case, the constraint cannot be created because it already exists. [source, error] ---- Constraint already exists: -Constraint( id=4, name='preExistingUnique', type='RELATIONSHIP_UNIQUENESS', schema=()-[:FRIENDS_WITH {nickname}]-(), ownedIndex=3 ) +Constraint( id=13, name='sequels', type='RELATIONSHIP UNIQUENESS', schema=()-[:SEQUEL_OF {order, seriesTitle}]-(), ownedIndex=12 ) ---- +[NOTE] +==== +The constraint type will be updated to say `RELATIONSHIP PROPERTY UNIQUENESS` in Neo4j version 6.0. +==== + ====== @@ -492,15 +487,19 @@ Constraint( id=4, name='preExistingUnique', type='RELATIONSHIP_UNIQUENESS', sche .+CREATE CONSTRAINT+ ====== -Create a property uniqueness constraint on the property `nickname` on relationships with the `FRIENDS_WITH` relationship type, when an index already exists on that relationship type and property combination. +Create a property uniqueness constraint on the property `order` on relationships with the `SEQUEL_OF` relationship type, when an index already exists on that relationship type and property combination. -// Set-up to get expected behavior: -// CREATE INDEX FOR ()-[friend:FRIENDS_WITH]-() ON (friend.nickname) +//// +[source, cypher, role=test-setup] +---- +CREATE INDEX sequel_order FOR ()-[sequel:SEQUEL_OF]-() ON (sequel.order) +---- +//// .Query -[source, cypher, role=test-skip] +[source, cypher, role=test-fail] ---- -CREATE CONSTRAINT FOR ()-[friend:FRIENDS_WITH]-() REQUIRE friend.nickname IS UNIQUE +CREATE CONSTRAINT sequel_series_title FOR ()-[sequel:SEQUEL_OF]-() REQUIRE (sequel.order) IS UNIQUE ---- In this case, the constraint cannot be created because there already exists an index covering that schema. @@ -508,7 +507,7 @@ In this case, the constraint cannot be created because there already exists an i .Error message [source, error] ---- -There already exists an index ()-[:FRIENDS_WITH {nickname}]-(). +There already exists an index ()-[:SEQUEL_OF {order}]-(). A constraint cannot be created until the index has been dropped. ---- @@ -523,27 +522,18 @@ A constraint cannot be created until the index has been dropped. .+CREATE RELATIONSHIP+ ====== -Create a `FRIENDS_WITH` relationship with an `nickname` that is not already in the database. - -// Set-up to get expected behavior: -// CREATE CONSTRAINT FOR ()-[friend:FRIENDS_WITH]-() REQUIRE friend.nickname IS UNIQUE +Create a `SEQUEL_OF` relationship with values for properties `order` and `seriesTitle` that are not already in the database. .Query -[source, cypher, role=test-skip] +[source, cypher, role=test-fail] ---- -CREATE (:Person {name: 'Josefin'})-[:FRIENDS_WITH {nickname: 'Mimi'}]->(:Person {name: 'Emilia'}) +CREATE (:Book {title: 'Spirit Walker'})-[:SEQUEL_OF {order: 1, seriesTitle: 'Chronicles of Ancient Darkness'}]->(:Book {title: 'Wolf Brother'}) ---- .Result [queryresult] ---- -+-------------------+ -| No data returned. | -+-------------------+ -Nodes created: 2 -Relationships created: 1 -Properties set: 3 -Labels added: 2 +Added 2 labels, created 2 nodes, set 4 properties, created 1 relationship. ---- ====== @@ -557,17 +547,13 @@ Labels added: 2 .+CREATE RELATIONSHIP+ ====== -Create a `FRIENDS_WITH` relationship with an `nickname` that is already used in the database. - -// Set-up to get expected behavior: -// CREATE CONSTRAINT FOR ()-[friend:FRIENDS_WITH]-() REQUIRE friend.nickname IS UNIQUE -// CREATE (:Person {name: 'Emma'}), (:Person {name: 'Josefin'})-[:FRIENDS_WITH {nickname: 'Mimi'}]->(:Person {name: 'Emilia'}) +Create a `SEQUEL_OF` relationship with values for properties `order` and `seriesTitle` that are already used in the database. .Query -[source, cypher, role=test-skip] +[source, cypher, role=test-fail] ---- -MATCH (emma:Person {name: 'Emma'}), (emilia:Person {name: 'Emilia'}) -CREATE (emma)-[:FRIENDS_WITH {nickname: 'Mimi'}]->(emilia) +MATCH (wolfBrother:Book {title: 'Wolf Brother'}), (spiritWalker:Book {title: 'Spirit Walker'}) +CREATE (spiritWalker)-[:SEQUEL_OF {order: 1, seriesTitle: 'Chronicles of Ancient Darkness'}]->(wolfBrother) ---- In this case, the relationship is not created in the graph. @@ -575,7 +561,7 @@ In this case, the relationship is not created in the graph. .Error message [source, error] ---- -Relationship(0) already exists with type `FRIENDS_WITH` and property `nickname` = 'Mimi' +Relationship(0) already exists with type `SEQUEL_OF` and properties `order` = 1, `seriesTitle` = 'Chronicles of Ancient Darkness' ---- ====== @@ -589,16 +575,20 @@ Relationship(0) already exists with type `FRIENDS_WITH` and property `nickname` .+CREATE CONSTRAINT+ ====== -Create a property uniqueness constraint on the property `nickname` on relationships with the `FRIENDS_WITH` relationship type when there are two relationships with the same `nickname`. +Create a property uniqueness constraint on the property `seriesTitle` on relationships with the `SEQUEL_OF` relationship type, when two relationships with the same `seriesTitle` already exist. -// Set-up to get expected behavior: -// CREATE (emma:Person {name: 'Emma'}), (josefin:Person {name: 'Josefin'}), (emilia:Person {name: 'Emilia'}) -// CREATE (josefin)-[:FRIENDS_WITH {nickname: 'Mimi'}]->(emilia), (emma)-[:FRIENDS_WITH {nickname: 'Mimi'}]->(emilia) +//// +[source, cypher, role=test-setup] +---- +MATCH (spiritWalker:Book {title: 'Spirit Walker'}) +CREATE (:Book {title: 'Soul Eater'})-[:SEQUEL_OF {order: 2, seriesTitle: 'Chronicles of Ancient Darkness'}]->(spiritWalker) +---- +//// .Query -[source, cypher, role=test-skip] +[source, cypher, role=test-fail] ---- -CREATE CONSTRAINT friends FOR ()-[friend:FRIENDS_WITH]-() REQUIRE friend.nickname IS UNIQUE +CREATE CONSTRAINT series_title FOR ()-[sequel:SEQUEL_OF]-() REQUIRE (sequel.seriesTitle) IS UNIQUE ---- In this case, the constraint cannot be created because it is violated by existing data. @@ -607,12 +597,25 @@ Either use xref::indexes-for-search-performance.adoc[] instead, or remove the of .Error message [source, error] ---- -Unable to create Constraint( name='friends', type='RELATIONSHIP_UNIQUENESS', schema=()-[:FRIENDS_WITH {nickname}]-() ): -Both Relationship(0) and Relationship(1) have the type `FRIENDS_WITH` and property `nickname` = 'Mimi' +Unable to create Constraint( name='series_title', type='RELATIONSHIP UNIQUENESS', schema=()-[:SEQUEL_OF {seriesTitle}]-() ): +Both Relationship(0) and Relationship(1) have the type `SEQUEL_OF` and property `seriesTitle` = 'Chronicles of Ancient Darkness' ---- ====== -//// + +The constraint creation fails on the first offending relationships that are found. +This does not guarantee that there are no other offending relationships in the data. +Therefore, all the data should be checked and cleaned up before re-attempting the constraint creation. + +This is an example `MATCH` query to find all offending relationships for the constraint above: + +.Query +[source, cypher] +---- +MATCH ()-[knows1:KNOWS]->(), ()-[knows2:KNOWS]->() +WHERE knows1.level = knows2.level AND NOT knows1 = knows2 +RETURN knows1, knows2 +---- [role=enterprise-edition] [[constraints-examples-node-property-existence]] @@ -652,14 +655,11 @@ FOR (author:Author) REQUIRE author.name IS NOT NULL Added 1 constraint. ---- -//// -TODO: Re-add this part when adding back relationship key and uniqueness constraints [NOTE] ==== -The statistics for property existence constraints will be split between nodes and relationships in Neo4j version 6.0. -For the node property existence constraints, they will say `Node property existence constraints`. +The detailed statistics view for property existence constraints, `Property existence constraints added: 1`, will be split between nodes and relationships in Neo4j version 6.0. +For the node property existence constraints, they will say `Node property existence constraints added: 1`. ==== -//// ====== @@ -679,7 +679,7 @@ This will ensure that no error is thrown and no constraint is created if any oth //// [source, cypher, role=test-setup] ---- -CREATE CONSTRAINT author_pseudonym +CREATE CONSTRAINT author_pseudonym FOR (author:Author) REQUIRE author.pseudonym IS UNIQUE ---- //// @@ -891,14 +891,11 @@ FOR ()-[wrote:WROTE]-() REQUIRE wrote.year IS NOT NULL Added 1 constraint. ---- -//// -TODO: Re-add this part when adding back relationship key and uniqueness constraints [NOTE] ==== -The statistics for property existence constraints will be split between nodes and relationships in Neo4j version 6.0. -For the relationship property existence constraints, they will say `Relationship property existence constraints`. +The detailed statistics view for property existence constraints, `Property existence constraints added: 1`, will be split between nodes and relationships in Neo4j version 6.0. +For the relationship property existence constraints, they will say `Relationship property existence constraints added: 1`. ==== -//// ====== @@ -918,7 +915,7 @@ This will ensure that no error is thrown and no constraint is created if any oth .Query [source, cypher] ---- -CREATE CONSTRAINT wrote_year IF NOT EXISTS +CREATE CONSTRAINT wrote_year IF NOT EXISTS FOR ()-[wrote:WROTE]-() REQUIRE wrote.year IS NOT NULL ---- @@ -1278,7 +1275,7 @@ There already exists an index called 'citizenship'. .+CREATE NODE+ ====== -Create an `Actor` node with a `firstname` and `surname` property. +Create an `Actor` node with `firstname` and `surname` properties. .Query [source, cypher] @@ -1399,10 +1396,7 @@ WHERE actor.born IS NULL RETURN actor, 'non-existing' AS reason ---- -//// -TODO: Re-add this part when adding back relationship key and uniqueness constraints [role=enterprise-edition] -TODO: Remove role=skip-test from queries once feature is introduced [[constraints-examples-relationship-key]] == Relationship key constraints @@ -1419,7 +1413,6 @@ It also ensures that all properties in the set are present. * xref::constraints/examples.adoc#constraints-removing-a-relationship-key-constrained-property[] * xref::constraints/examples.adoc#constraints-fail-to-create-a-relationship-key-constraint-due-to-existing-relationship[] - [discrete] [[constraints-create-a-relationship-key-constraint]] === Create a relationship key constraint @@ -1431,19 +1424,16 @@ When creating a relationship key constraint, a name can be provided. ====== .Query -[source, cypher, role=test-skip] +[source, cypher] ---- -CREATE CONSTRAINT constraint_name -FOR ()-[r:ROAD]-() REQUIRE (r.startPoint, r.endPoint) IS RELATIONSHIP KEY +CREATE CONSTRAINT knows_since_how +FOR ()-[knows:KNOWS]-() REQUIRE (knows.since, knows.how) IS RELATIONSHIP KEY ---- .Result [queryresult] ---- -+-------------------+ -| No data returned. | -+-------------------+ -Relationship key constraints added: 1 +Added 1 constraint. ---- ====== @@ -1461,24 +1451,19 @@ This will ensure that no error is thrown and no constraint is created if any oth .+CREATE CONSTRAINT+ ====== -// Set-up to get expected behavior: -// CREATE CONSTRAINT FOR ()-[r:ROAD]-() REQUIRE (r.startPoint, r.endPoint) IS RELATIONSHIP KEY - .Query -[source, cypher, role=test-skip] +[source, cypher] ---- -CREATE CONSTRAINT constraint_name IF NOT EXISTS -FOR ()-[r:ROAD]-() REQUIRE (r.startPoint, r.endPoint) IS RELATIONSHIP KEY +CREATE CONSTRAINT knows IF NOT EXISTS +FOR ()-[knows:KNOWS]-() REQUIRE (knows.since, knows.how) IS RELATIONSHIP KEY ---- -Assuming a relationship key constraint on `()-[:ROAD {startPoint, endPoint}]-()` already existed: +Assuming a relationship key constraint on `()-[:KNOWS {since, how}]-()` already existed: .Result [queryresult] ---- -+--------------------------------------------+ -| No data returned, and nothing was changed. | -+--------------------------------------------+ +(no changes, no records) ---- ====== @@ -1501,10 +1486,10 @@ The only valid value for the index provider is: ====== .Query -[source, cypher, role=test-skip] +[source, cypher] ---- -CREATE CONSTRAINT constraint_with_provider -FOR ()-[r:ROAD]-() REQUIRE (r.startPoint, r.endPoint) IS REL KEY +CREATE CONSTRAINT rel_constraint_with_provider +FOR ()-[knows:KNOWS]-() REQUIRE (knows.since) IS REL KEY OPTIONS { indexProvider: 'range-1.0' } @@ -1513,10 +1498,7 @@ OPTIONS { .Result [queryresult] ---- -+-------------------+ -| No data returned. | -+-------------------+ -Relationship key constraints added: 1 +Added 1 constraint. ---- ====== @@ -1532,15 +1514,19 @@ There is no valid index configuration values for the constraint-backing range in .+CREATE CONSTRAINT+ ====== -Create a relationship key constraint on the properties `startPoint` and `endPoint` on relationships with the `ROAD` relationship type, when a property uniqueness constraint already exists on the same relationship type and property combination. +Create a relationship key constraint on the property `how` on relationships with the `KNOWS` relationship type, when a property uniqueness constraint already exists on the same relationship type and property combination. -// Set-up to get expected behavior: -// CREATE CONSTRAINT preExistingUnique FOR ()-[r:ROAD]-() REQUIRE (r.startPoint, r.endPoint) IS UNIQUE +//// +[source, cypher, role=test-setup] +---- +CREATE CONSTRAINT preExisting_how FOR ()-[knows:KNOWS]-() REQUIRE (knows.how) IS UNIQUE +---- +//// .Query -[source, cypher, role=test-skip] +[source, cypher, role=test-fail] ---- -CREATE CONSTRAINT FOR ()-[r:ROAD]-() REQUIRE (r.startPoint, r.endPoint) IS REL KEY +CREATE CONSTRAINT knows_how FOR ()-[knows:KNOWS]-() REQUIRE (knows.how) IS REL KEY ---- In this case, the constraint cannot be created because there already exists a conflicting constraint on that relationship type and property combination. @@ -1549,9 +1535,14 @@ In this case, the constraint cannot be created because there already exists a co [source, error] ---- Constraint already exists: -Constraint( id=4, name='preExistingUnique', type='RELATIONSHIP_UNIQUENESS', schema=()-[:ROAD {startPoint, endPoint}]-(), ownedIndex=3 ) +Constraint( id=34, name='preExisting_how', type='RELATIONSHIP UNIQUENESS', schema=()-[:KNOWS {how}]-(), ownedIndex=33 ) ---- +[NOTE] +==== +The constraint type for relationship property uniqueness constraints will be updated to say `RELATIONSHIP PROPERTY UNIQUENESS` in Neo4j version 6.0. +==== + ====== @@ -1563,16 +1554,20 @@ Constraint( id=4, name='preExistingUnique', type='RELATIONSHIP_UNIQUENESS', sche .+CREATE CONSTRAINT+ ====== -Create a named relationship key constraint on the property `coordinates` on relationships with the `INTERSECTION` relationship type, when an index already exists with the given name. +Create a named relationship key constraint on the property `level` on relationships with the `KNOWS` relationship type, when an index already exists with the given name. -// Set-up to get expected behavior: -// CREATE INDEX intersections FOR ()-[intersect:Roundabout]-() ON (intersect.coordinates) +//// +[source, cypher, role=test-setup] +---- +CREATE INDEX knows FOR ()-[know:KNOW]-() ON (know.levels) +---- +//// .Query -[source, cypher, role=test-skip] +[source, cypher, role=test-fail] ---- -CREATE CONSTRAINT intersections -FOR ()-[r:INTERSECTION]-() REQUIRE (r.coordinates) IS REL KEY +CREATE CONSTRAINT knows +FOR ()-[knows:KNOWS]-() REQUIRE (knows.level) IS REL KEY ---- In this case, the constraint cannot be created because there already exists an index with the given name. @@ -1580,7 +1575,7 @@ In this case, the constraint cannot be created because there already exists an i .Error message [source, error] ---- -There already exists an index called 'intersections'. +There already exists an index called 'knows'. ---- ====== @@ -1594,27 +1589,18 @@ There already exists an index called 'intersections'. .+CREATE RELATIONSHIP+ ====== -Create a `ROAD` relationship with both a `startPoint` and `endPoint` property. - -// Set-up to get expected behavior: -// CREATE CONSTRAINT FOR ()-[r:ROAD]-() REQUIRE (r.startPoint, r.endPoint) IS REL KEY -// CREATE (:Intersection {name: 'a', coordinates: point({x: 1, y:2})}), (:Intersection {name: 'b', coordinates: point({x: 2, y:5})}) +Create a `KNOWS` relationship with both `since` and `how` properties and a relationship key constraint on `:KNOWS(since, how)`. .Query -[source, cypher, role=test-skip] +[source, cypher] ---- -MATCH (a:Intersection {name: 'a'}), (b:Intersection {name: 'b'}) -CREATE (a)-[:ROAD {startPoint: a.coordinates, endPoint: b.coordinates}]->(b) +CREATE (:Actor {firstname: 'Jensen', surname: 'Ackles'})-[:KNOWS {since: 2008, how: 'coworkers'}]->(:Actor {firstname: 'Misha', surname: 'Collins'}) ---- .Result [queryresult] ---- -+-------------------+ -| No data returned. | -+-------------------+ -Relationships created: 1 -Properties set: 2 +Added 2 labels, created 2 nodes, set 6 properties, created 1 relationship. ---- ====== @@ -1628,17 +1614,13 @@ Properties set: 2 .+CREATE RELATIONSHIP+ ====== -Trying to create a `INTERSECTION` relationship without a `coordinates` property, given a relationship key constraint on `:INTERSECTION(coordinates)`, will fail. - -// Set-up to get expected behavior: -// CREATE CONSTRAINT FOR ()-[r:INTERSECTION]-() REQUIRE (r.coordinates) IS REL KEY -// CREATE (:Road {name: 'a'}), (:Road {name: 'b'}) +Trying to create a `KNOWS` relationship without a `since` property, given a relationship key constraint on `:KNOWS(since, how)`, will fail. .Query -[source, cypher, role=test-skip] +[source, cypher, role=test-fail] ---- -MATCH (a:Road {name: 'a'}), (b:Road {name: 'b'}) -CREATE (a)-[:INTERSECTION]->(b) +MATCH (jensen:Actor {firstname: 'Jensen', surname: 'Ackles'}), (misha:Actor {firstname: 'Misha', surname: 'Collins'}) +CREATE (misha)-[:KNOWS {how: 'coworkers'}]->(jensen) ---- In this case, the relationship is not created in the graph. @@ -1646,7 +1628,7 @@ In this case, the relationship is not created in the graph. .Error message [source, error] ---- -Relationship(0) with type `INTERSECTION` must have the property `coordinates` +Relationship(0) already exists with type `KNOWS` and property `how` = 'coworkers' ---- ====== @@ -1660,17 +1642,12 @@ Relationship(0) with type `INTERSECTION` must have the property `coordinates` .+REMOVE PROPERTY+ ====== -Trying to remove the `endPoint` property from an existing relationship `ROAD`, given a `RELATIONSHIP KEY` constraint on `:ROAD(startPoint, endPoint)`. - -// Set-up to get expected behavior: -// CREATE CONSTRAINT FOR ()-[r:ROAD]-() REQUIRE (r.startPoint, r.endPoint) IS REL KEY -// CREATE (a:Intersection {name: 'a', coordinates: point({x: 1, y:2})}), (b:Intersection {name: 'b', coordinates: point({x: 2, y:5})}) -// CREATE (a)-[:ROAD {startPoint: a.coordinates, endPoint: b.coordinates}]->(b) +Trying to remove the `since` property from an existing relationship `KNOWS`, given a `RELATIONSHIP KEY` constraint on `:KNOWS(since, how)`. .Query -[source, cypher, role=test-skip] +[source, cypher, role=test-fail] ---- -MATCH ()-[r:ROAD {startPoint: point({x: 1, y:2}), endPoint: point({x: 2, y:5})}]->() REMOVE r.endPoint +MATCH ()-[knows:KNOWS {since: 2008, how: 'coworkers'}]->() REMOVE knows.since ---- In this case, the property is not removed. @@ -1678,7 +1655,7 @@ In this case, the property is not removed. .Error message [source, error] ---- -Relationship(0) with type `ROAD` must have the properties (`startPoint`, `endPoint`) +Relationship(0) with type `KNOWS` must have the properties (`since`, `how`) ---- ====== @@ -1692,17 +1669,21 @@ Relationship(0) with type `ROAD` must have the properties (`startPoint`, `endPoi .+CREATE CONSTRAINT+ ====== -Trying to create a relationship key constraint on the property `coordinates` on relationships with the `INTERSECTION` relationship type will fail when two relationships with identical `coordinates` already exists in the database. +Trying to create a relationship key constraint on the property `level` on relationships with the `KNOWS` relationship type will fail when two relationships with identical `level` property values already exist in the database. -// Set-up to get expected behavior: -// CREATE (a:Road {name: 'a'}), (b:Road {name: 'b'}) -// CREATE (a)-[:INTERSECTION {coordinates: point({x:1, y:2})}]->(b) -// CREATE (a)<-[:INTERSECTION {coordinates: point({x:1, y:2})}]-(b) +//// +[source, cypher, role=test-setup] +---- +MATCH (jensen:Actor {firstname: 'Jensen', surname: 'Ackles'})-[knows:KNOWS {since: 2008, how: 'coworkers'}]->(:Actor {firstname: 'Misha', surname: 'Collins'}) +SET knows.level = 10 +CREATE (jensen)-[:KNOWS {since: 2005, how: 'costars', level: 10}]->(:Actor {firstname: 'Jared', surname: 'Padalecki'}) +---- +//// .Query -[source, cypher, role=test-skip] +[source, cypher, role=test-fail] ---- -CREATE CONSTRAINT intersectionConstraint FOR ()-[r:INTERSECTION]-() REQUIRE (r.coordinates) IS REL KEY +CREATE CONSTRAINT knows_level FOR ()-[knows:KNOWS]-() REQUIRE (knows.level) IS REL KEY ---- In this case, the relationship key constraint cannot be created because it is violated by existing data. @@ -1711,12 +1692,31 @@ Either use xref::indexes-for-search-performance.adoc[] instead, or remove the of .Error message [source, error] ---- -Unable to create Constraint( name='intersectionConstraint', type='RELATIONSHIP KEY', schema=()-[:INTERSECTION {coordinates}]-() ): -Both Relationship(0) and Relationship(1) have the type `INTERSECTION` and property `coordinates` = {geometry: {type: "Point", coordinates: [1.0, 2.0], crs: {type: link, properties: {href: "http://spatialreference.org/ref/sr-org/7203/", code: 7203}}}} +Unable to create Constraint( name='knows_level', type='RELATIONSHIP KEY', schema=()-[:KNOWS {level}]-() ): +Both Relationship(0) and Relationship(1) have the type `KNOWS` and property `level` = 10 ---- ====== -//// + +The constraint creation fails on the first offending relationships that are found. +This does not guarantee that there are no other offending relationships in the data. +Therefore, all the data should be checked and cleaned up before re-attempting the constraint creation. + +This is an example `MATCH` query to find all offending relationships for the constraint above: + +.Query +[source, cypher] +---- +MATCH ()-[knows1:KNOWS]->(), ()-[knows2:KNOWS]->() +WHERE knows1.level = knows2.level AND NOT knows1 = knows2 +UNWIND [knows1, knows2] AS knows +RETURN knows, 'non-unique' AS reason +UNION +MATCH ()-[knows:KNOWS]->() +WHERE knows.level IS NULL +RETURN knows, 'non-existing' AS reason +---- + [[constraints-examples-drop-constraint]] == Drop a constraint by name @@ -1730,9 +1730,7 @@ Both Relationship(0) and Relationship(1) have the type `INTERSECTION` and proper === Drop a constraint A constraint can be dropped using the name with the `DROP CONSTRAINT constraint_name` command. -It is the same command for uniqueness, property existence, and node key constraints. -// TODO: Switch the row above to the one below when adding back relationship key and uniqueness constraints -//It is the same command for uniqueness, property existence, and node/relationship key constraints. +It is the same command for uniqueness, property existence, and node/relationship key constraints. The name of the constraint can be found using the xref::constraints/syntax.adoc#constraints-syntax-list[`SHOW CONSTRAINTS` command], given in the output column `name`. @@ -1759,9 +1757,7 @@ Removed 1 constraint. === Drop a non-existing constraint If it is uncertain if any constraint with a given name exists and you want to drop it if it does but not get an error should it not, use `IF EXISTS`. -It is the same command for uniqueness, property existence, and node constraints. -// TODO: Switch the row above to the one below when adding back relationship key and uniqueness constraints -//It is the same command for uniqueness, property existence, and node/relationship key constraints. +It is the same command for uniqueness, property existence, and node/relationship key constraints. .+DROP CONSTRAINT+ ====== @@ -1813,44 +1809,48 @@ SHOW CONSTRAINTS [queryresult] ---- -╒════╤════════════════════════════╤═════════════════════════════════╤══════════════╤═══════════════╤═══════════════════════╤════════════════════════════╕ -│"id"│"name" │"type" │"entityType" │"labelsOrTypes"│"properties" │"ownedIndex" │ -╞════╪════════════════════════════╪═════════════════════════════════╪══════════════╪═══════════════╪═══════════════════════╪════════════════════════════╡ -│16 │"actor_fullname" │"NODE_KEY" │"NODE" │["Actor"] │["firstname","surname"]│"actor_fullname" │ -├────┼────────────────────────────┼─────────────────────────────────┼──────────────┼───────────────┼───────────────────────┼────────────────────────────┤ -│10 │"author_name" │"NODE_PROPERTY_EXISTENCE" │"NODE" │["Author"] │["name"] │null │ -├────┼────────────────────────────┼─────────────────────────────────┼──────────────┼───────────────┼───────────────────────┼────────────────────────────┤ -│12 │"author_pseudonym" │"UNIQUENESS" │"NODE" │["Author"] │["pseudonym"] │"author_pseudonym" │ -├────┼────────────────────────────┼─────────────────────────────────┼──────────────┼───────────────┼───────────────────────┼────────────────────────────┤ -│4 │"book_isbn2" │"UNIQUENESS" │"NODE" │["Book"] │["isbn2"] │"book_isbn2" │ -├────┼────────────────────────────┼─────────────────────────────────┼──────────────┼───────────────┼───────────────────────┼────────────────────────────┤ -│6 │"constraint_with_options" │"UNIQUENESS" │"NODE" │["Book"] │["prop1","prop2"] │"constraint_with_options" │ -├────┼────────────────────────────┼─────────────────────────────────┼──────────────┼───────────────┼───────────────────────┼────────────────────────────┤ -│18 │"constraint_with_provider" │"NODE_KEY" │"NODE" │["Actor"] │["surname"] │"constraint_with_provider" │ -├────┼────────────────────────────┼─────────────────────────────────┼──────────────┼───────────────┼───────────────────────┼────────────────────────────┤ -│20 │"preExisting_actor_name_age"│"UNIQUENESS" │"NODE" │["Actor"] │["firstname","age"] │"preExisting_actor_name_age"│ -├────┼────────────────────────────┼─────────────────────────────────┼──────────────┼───────────────┼───────────────────────┼────────────────────────────┤ -│8 │"preExisting_book_published"│"UNIQUENESS" │"NODE" │["Book"] │["published"] │"preExisting_book_published"│ -├────┼────────────────────────────┼─────────────────────────────────┼──────────────┼───────────────┼───────────────────────┼────────────────────────────┤ -│14 │"wrote_locations" │"RELATIONSHIP_PROPERTY_EXISTENCE"│"RELATIONSHIP"│["WROTE"] │["location"] │null │ -├────┼────────────────────────────┼─────────────────────────────────┼──────────────┼───────────────┼───────────────────────┼────────────────────────────┤ -│13 │"wrote_year" │"RELATIONSHIP_PROPERTY_EXISTENCE"│"RELATIONSHIP"│["WROTE"] │["year"] │null │ -└────┴────────────────────────────┴─────────────────────────────────┴──────────────┴───────────────┴───────────────────────┴────────────────────────────┘ -10 rows +╒════╤══════════════════════════════╤═════════════════════════════════╤══════════════╤═══════════════╤════════════════════════════════╤══════════════════════════════╕ +│"id"│"name" │"type" │"entityType" │"labelsOrTypes"│"properties" │"ownedIndex" │ +╞════╪══════════════════════════════╪═════════════════════════════════╪══════════════╪═══════════════╪════════════════════════════════╪══════════════════════════════╡ +│23 │"actor_fullname" │"NODE_KEY" │"NODE" │["Actor"] │["firstname","surname"] │"actor_fullname" │ +├────┼──────────────────────────────┼─────────────────────────────────┼──────────────┼───────────────┼────────────────────────────────┼──────────────────────────────┤ +│16 │"author_name" │"NODE_PROPERTY_EXISTENCE" │"NODE" │["Author"] │["name"] │null │ +├────┼──────────────────────────────┼─────────────────────────────────┼──────────────┼───────────────┼────────────────────────────────┼──────────────────────────────┤ +│19 │"author_pseudonym" │"UNIQUENESS" │"NODE" │["Author"] │["pseudonym"] │"author_pseudonym" │ +├────┼──────────────────────────────┼─────────────────────────────────┼──────────────┼───────────────┼────────────────────────────────┼──────────────────────────────┤ +│6 │"book_isbn2" │"UNIQUENESS" │"NODE" │["Book"] │["isbn2"] │"book_isbn2" │ +├────┼──────────────────────────────┼─────────────────────────────────┼──────────────┼───────────────┼────────────────────────────────┼──────────────────────────────┤ +│8 │"constraint_with_options" │"UNIQUENESS" │"NODE" │["Book"] │["prop1","prop2"] │"constraint_with_options" │ +├────┼──────────────────────────────┼─────────────────────────────────┼──────────────┼───────────────┼────────────────────────────────┼──────────────────────────────┤ +│25 │"constraint_with_provider" │"NODE_KEY" │"NODE" │["Actor"] │["surname"] │"constraint_with_provider" │ +├────┼──────────────────────────────┼─────────────────────────────────┼──────────────┼───────────────┼────────────────────────────────┼──────────────────────────────┤ +│30 │"knows_since_how" │"RELATIONSHIP_KEY" │"RELATIONSHIP"│["KNOWS"] │["since","how"] │"knows_since_how" │ +├────┼──────────────────────────────┼─────────────────────────────────┼──────────────┼───────────────┼────────────────────────────────┼──────────────────────────────┤ +│27 │"preExisting_actor_name_age" │"UNIQUENESS" │"NODE" │["Actor"] │["firstname","age"] │"preExisting_actor_name_age" │ +├────┼──────────────────────────────┼─────────────────────────────────┼──────────────┼───────────────┼────────────────────────────────┼──────────────────────────────┤ +│10 │"preExisting_book_published" │"UNIQUENESS" │"NODE" │["Book"] │["published"] │"preExisting_book_published" │ +├────┼──────────────────────────────┼─────────────────────────────────┼──────────────┼───────────────┼────────────────────────────────┼──────────────────────────────┤ +│34 │"preExisting_how" │"RELATIONSHIP_UNIQUENESS" │"RELATIONSHIP"│["KNOWS"] │["how"] │"preExisting_how" │ +├────┼──────────────────────────────┼─────────────────────────────────┼──────────────┼───────────────┼────────────────────────────────┼──────────────────────────────┤ +│15 │"rel_constraint_with_options" │"RELATIONSHIP_UNIQUENESS" │"RELATIONSHIP"│["SEQUEL_OF"] │["order","seriesTitle","number"]│"rel_constraint_with_options" │ +├────┼──────────────────────────────┼─────────────────────────────────┼──────────────┼───────────────┼────────────────────────────────┼──────────────────────────────┤ +│32 │"rel_constraint_with_provider"│"RELATIONSHIP_KEY" │"RELATIONSHIP"│["KNOWS"] │["since"] │"rel_constraint_with_provider"│ +├────┼──────────────────────────────┼─────────────────────────────────┼──────────────┼───────────────┼────────────────────────────────┼──────────────────────────────┤ +│13 │"sequels" │"RELATIONSHIP_UNIQUENESS" │"RELATIONSHIP"│["SEQUEL_OF"] │["order","seriesTitle"] │"sequels" │ +├────┼──────────────────────────────┼─────────────────────────────────┼──────────────┼───────────────┼────────────────────────────────┼──────────────────────────────┤ +│21 │"wrote_locations" │"RELATIONSHIP_PROPERTY_EXISTENCE"│"RELATIONSHIP"│["WROTE"] │["location"] │null │ +├────┼──────────────────────────────┼─────────────────────────────────┼──────────────┼───────────────┼────────────────────────────────┼──────────────────────────────┤ +│20 │"wrote_year" │"RELATIONSHIP_PROPERTY_EXISTENCE"│"RELATIONSHIP"│["WROTE"] │["year"] │null │ +└────┴──────────────────────────────┴─────────────────────────────────┴──────────────┴───────────────┴────────────────────────────────┴──────────────────────────────┘ +15 rows ---- -//// -TODO: Update the above table of constraints once the relationship key and uniqueness constraints are no longer behind a feature flag. -//// - -//// -TODO: Re-add this part when adding back relationship key and uniqueness constraints [NOTE] ==== The `type` column returns `UNIQUENESS` for the node property uniqueness constraint and `RELATIONSHIP_UNIQUENESS` for the relationship property uniqueness constraint. -The `type` for node property uniqueness constraint will be updated to `NODE_UNIQUENESS` in Neo4j version 6.0. +This will be updated in Neo4j version 6.0. +Node property uniqueness constraints will be updated to `NODE_PROPERTY_UNIQUENESS` and relationship property uniqueness constraints to `RELATIONSHIP_PROPERTY_UNIQUENESS`. ==== -//// ====== @@ -1884,9 +1884,9 @@ To get all columns, use `+SHOW INDEXES YIELD * WHERE ...+`. ╒════╤═════════════════╤═════════════════════════════════╤══════════════╤═══════════════╤════════════╤════════════╕ │"id"│"name" │"type" │"entityType" │"labelsOrTypes"│"properties"│"ownedIndex"│ ╞════╪═════════════════╪═════════════════════════════════╪══════════════╪═══════════════╪════════════╪════════════╡ -│14 │"wrote_locations"│"RELATIONSHIP_PROPERTY_EXISTENCE"│"RELATIONSHIP"│["WROTE"] │["location"]│null │ +│21 │"wrote_locations"│"RELATIONSHIP_PROPERTY_EXISTENCE"│"RELATIONSHIP"│["WROTE"] │["location"]│null │ ├────┼─────────────────┼─────────────────────────────────┼──────────────┼───────────────┼────────────┼────────────┤ -│13 │"wrote_year" │"RELATIONSHIP_PROPERTY_EXISTENCE"│"RELATIONSHIP"│["WROTE"] │["year"] │null │ +│20 │"wrote_year" │"RELATIONSHIP_PROPERTY_EXISTENCE"│"RELATIONSHIP"│["WROTE"] │["year"] │null │ └────┴─────────────────┴─────────────────────────────────┴──────────────┴───────────────┴────────────┴────────────┘ 2 rows ---- diff --git a/modules/ROOT/pages/constraints/index.adoc b/modules/ROOT/pages/constraints/index.adoc index e356d748a..ac1ab9687 100644 --- a/modules/ROOT/pages/constraints/index.adoc +++ b/modules/ROOT/pages/constraints/index.adoc @@ -18,13 +18,10 @@ Unique node property constraints, or node property uniqueness constraints, ensur For property uniqueness constraints on multiple properties, the combination of the property values is unique. Node property uniqueness constraints do not require all nodes to have a unique value for the properties listed (nodes without all properties are not subject to this rule). -// TODO: Re-add this part when adding back relationship key and uniqueness constraints -//// *Unique relationship property constraints*:: Unique relationship property constraints, or relationship property uniqueness constraints, ensure that property values are unique for all relationships with a specific type. For property uniqueness constraints on multiple properties, the combination of the property values is unique. Relationship property uniqueness constraints do not require all relationships to have a unique value for the properties listed (relationships without all properties are not subject to this rule). -//// *Node property existence constraints* label:enterprise-edition[]:: Node property existence constraints ensure that a property exists for all nodes with a specific label. @@ -50,8 +47,6 @@ Queries attempting to do any of the following will fail: * Remove one of the mandatory properties. * Update the properties so that the combination of property values is no longer unique. -// TODO: Re-add this part when adding back relationship key and uniqueness constraints -//// *Relationship key constraints* label:enterprise-edition[]:: Relationship key constraints ensure that, for a given type and set of properties: + @@ -65,14 +60,11 @@ Queries attempting to do any of the following will fail: * Create new relationships without all the properties or where the combination of property values is not unique. * Remove one of the mandatory properties. * Update the properties so that the combination of property values is no longer unique. -//// [NOTE] ==== -Node key constraints, node property existence constraints, and relationship property existence constraints are only available in Neo4j Enterprise Edition. -// TODO: Switch the row above to the one below when adding back relationship key and uniqueness constraints -//Node key constraints, relationship key constraints, node property existence constraints, and relationship property existence constraints are only available in Neo4j Enterprise Edition. +Node key constraints, relationship key constraints, node property existence constraints, and relationship property existence constraints are not available in Neo4j Community Edition. Databases containing one of these constraint types cannot be opened using Neo4j Community Edition. ==== @@ -81,26 +73,15 @@ Databases containing one of these constraint types cannot be opened using Neo4j Creating a constraint has the following implications on indexes: -* Adding a node key or property uniqueness constraint on a single property also adds an index on that property, and therefore, an index of the same index type, label, and property combination cannot be added separately. -* Adding a node key or property uniqueness constraint for a set of properties also adds an index on those properties, and therefore, an index of the same index type, label, and properties combination cannot be added separately. -* Cypher will use these indexes for lookups just like other indexes. - Refer to xref::indexes-for-search-performance.adoc[] for more details on indexes. -* If a node key or property uniqueness constraint is dropped and the backing index is still required, the index need to be created explicitly. - -//// -TODO: Switch the part above to the one below when adding back relationship key and uniqueness constraints * Adding a node key, relationship key, or property uniqueness constraint on a single property also adds an index on that property, and therefore, an index of the same index type, label/relationship type, and property combination cannot be added separately. * Adding a node key, relationship key, or property uniqueness constraint for a set of properties also adds an index on those properties, and therefore, an index of the same index type, label/relationship type, and properties combination cannot be added separately. * Cypher will use these indexes for lookups just like other indexes. Refer to xref::indexes-for-search-performance.adoc[] for more details on indexes. * If a node key, relationship key, or property uniqueness constraint is dropped and the backing index is still required, the index need to be created explicitly. -//// Additionally, the following is true for constraints: -* A given label can have multiple constraints, and uniqueness and property existence constraints can be combined on the same property. -// TODO: Switch the row above to the one below when adding back relationship key and uniqueness constraints -//* A given label or relationship type can have multiple constraints, and uniqueness and property existence constraints can be combined on the same property. +* A given label or relationship type can have multiple constraints, and uniqueness and property existence constraints can be combined on the same property. * Adding constraints is an atomic operation that can take a while -- all existing data has to be scanned before Neo4j DBMS can turn the constraint 'on'. * Best practice is to give the constraint a name when it is created. If the constraint is not explicitly named, it will get an auto-generated name. diff --git a/modules/ROOT/pages/constraints/syntax.adoc b/modules/ROOT/pages/constraints/syntax.adoc index 76909c2fe..75cf3d014 100644 --- a/modules/ROOT/pages/constraints/syntax.adoc +++ b/modules/ROOT/pages/constraints/syntax.adoc @@ -56,8 +56,6 @@ REQUIRE (n.propertyName_1, ..., n.propertyName_n) IS [NODE] UNIQUE Index provider can be specified using the `OPTIONS` clause. -//// -TODO: Re-add this part when adding back relationship key and uniqueness constraints [[constraints-syntax-create-rel-unique]] [discrete] === Create a relationship property uniqueness constraint @@ -81,7 +79,6 @@ REQUIRE (r.propertyName_1, ..., r.propertyName_n) IS [REL[ATIONSHIP]] UNIQUE ---- Index provider can be specified using the `OPTIONS` clause. -//// [[constraints-syntax-create-node-exists]] @@ -149,8 +146,6 @@ REQUIRE (n.propertyName_1, ..., n.propertyName_n) IS [NODE] KEY Index provider can be specified using the `OPTIONS` clause. -//// -TODO: Re-add this part when adding back relationship key and uniqueness constraints [[constraints-syntax-create-rel-key]] [discrete] === Create a relationship key constraint label:enterprise-edition[] @@ -174,7 +169,6 @@ REQUIRE (r.propertyName_1, ..., r.propertyName_n) IS [REL[ATIONSHIP]] KEY ---- Index provider can be specified using the `OPTIONS` clause. -//// [[constraints-syntax-drop]] @@ -208,21 +202,6 @@ Listing constraints requires the xref::administration/access-control/database-ad The simple version of the command allows for a `WHERE` clause and will give back the default set of output columns: -[source, syntax, role="noheader", indent=0] ----- -SHOW [ - ALL - |UNIQUE[NESS] - |NODE [PROPERTY] EXIST[ENCE] - |REL[ATIONSHIP] [PROPERTY] EXIST[ENCE] - |[PROPERTY] EXIST[ENCE] - |NODE KEY -] CONSTRAINT[S] - [WHERE expression] ----- - -//// -TODO: Switch the syntax above to the one below when adding back relationship key and uniqueness constraints [source, syntax, role="noheader", indent=0] ---- SHOW [ @@ -239,27 +218,9 @@ SHOW [ ] CONSTRAINT[S] [WHERE expression] ---- -//// To get the full set of output columns, a yield clause is needed: -[source, syntax, role="noheader", indent=0] ----- -SHOW [ - ALL - |UNIQUE[NESS] - |NODE [PROPERTY] EXIST[ENCE] - |REL[ATIONSHIP] [PROPERTY] EXIST[ENCE] - |[PROPERTY] EXIST[ENCE] - |NODE KEY -] CONSTRAINT[S] -YIELD { * | field[, ...] } [ORDER BY field[, ...]] [SKIP n] [LIMIT n] - [WHERE expression] - [RETURN field[, ...] [ORDER BY field[, ...]] [SKIP n] [LIMIT n]] ----- - -//// -TODO: Switch the syntax above to the one below when adding back relationship key and uniqueness constraints [source, syntax, role="noheader", indent=0] ---- SHOW [ @@ -278,7 +239,6 @@ YIELD { * | field[, ...] } [ORDER BY field[, ...]] [SKIP n] [LIMIT n] [WHERE expression] [RETURN field[, ...] [ORDER BY field[, ...]] [SKIP n] [LIMIT n]] ---- -//// The type filtering keywords filters the returned constraints on constraint type: @@ -293,18 +253,14 @@ The type filtering keywords filters the returned constraints on constraint type: | Returns all constraints, no filtering on constraint type. This is the default if none is given. -// TODO: Re-add these parts when adding back relationship key and uniqueness constraints -//|NODE UNIQUE[NESS] -//| Returns the node property uniqueness constraints. +|NODE UNIQUE[NESS] +| Returns the node property uniqueness constraints. -//|REL[ATIONSHIP] UNIQUE[NESS] -//| Returns the relationship property uniqueness constraints. +|REL[ATIONSHIP] UNIQUE[NESS] +| Returns the relationship property uniqueness constraints. |UNIQUE[NESS] -| Returns all property uniqueness constraints. -// TODO: Switch the part above to the one below when adding back relationship key and uniqueness constraints -//|UNIQUE[NESS] -//| Returns all property uniqueness constraints, for both nodes and relationships. +| Returns all property uniqueness constraints, for both nodes and relationships. |NODE [PROPERTY] EXIST[ENCE] | Returns the node property existence constraints. @@ -318,12 +274,11 @@ This is the default if none is given. |NODE KEY | Returns the node key constraints. -// TODO: Re-add these parts when adding back relationship key and uniqueness constraints -//|REL[ATIONSHIP] KEY -//| Returns the relationship key constraints. +|REL[ATIONSHIP] KEY +| Returns the relationship key constraints. -//|KEY -//| Returns all node and relationship key constraints. +|KEY +| Returns all node and relationship key constraints. |=== @@ -344,9 +299,7 @@ The returned columns from the show command is: | STRING | type -| The ConstraintType of this constraint (`UNIQUENESS`, `NODE_PROPERTY_EXISTENCE`, `RELATIONSHIP_PROPERTY_EXISTENCE`, or `NODE_KEY`). label:default-output[] -// TODO: Switch the row above to the one below when adding back relationship key and uniqueness constraints -//| The ConstraintType of this constraint (`UNIQUENESS` (node uniqueness), `RELATIONSHIP_UNIQUENESS`, `NODE_PROPERTY_EXISTENCE`, `RELATIONSHIP_PROPERTY_EXISTENCE`, `NODE_KEY`, or `RELATIONSHIP_KEY`). label:default-output[] +| The ConstraintType of this constraint (`UNIQUENESS` (node uniqueness), `RELATIONSHIP_UNIQUENESS`, `NODE_PROPERTY_EXISTENCE`, `RELATIONSHIP_PROPERTY_EXISTENCE`, `NODE_KEY`, or `RELATIONSHIP_KEY`). label:default-output[] | STRING | entityType diff --git a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc index f55d915a2..22cd2acdc 100644 --- a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc +++ b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc @@ -36,6 +36,7 @@ a| The Cypher query option `connectComponentsPlanner` is deprecated and will be removed without a replacement. The product's default behavior of using a cost-based IDP search algorithm when combining sub-plans will be kept. + |=== @@ -54,8 +55,44 @@ label:updated[] ALTER DATABASE ... [WAIT [n [SEC[OND[S]]]]\|NOWAIT] ---- a| -New sub-clause `WAIT` for `ALTER DATABASE`. -This enables adding a waiting clause to specify a time limit in which the command must be completed and returned. +New sub-clause `WAIT` for `ALTER DATABASE`. +This enables adding a waiting clause to specify a time limit in which the command must be completed and returned. + +a| +label:functionality[] +label:new[] +[source, cypher, role="noheader"] +---- +CREATE CONSTRAINT name FOR ()-[r:TYPE]-() REQUIRE r.prop IS UNIQUE + +CREATE CONSTRAINT name FOR ()-[r:TYPE]-() REQUIRE r.prop IS RELATIONSHIP KEY +---- +a| + +Added relationship xref:constraints/syntax.adoc#constraints-syntax-create-rel-key[key] and xref:constraints/syntax.adoc#constraints-syntax-create-rel-unique[uniqueness] constraints. + +a| +label:functionality[] +label:new[] +[source, cypher, role="noheader"] +---- +SHOW NODE UNIQUE[NESS] CONSTRAINTS + +SHOW REL[ATIONSHIP] UNIQUE[NESS] CONSTRAINTS + +SHOW UNIQUE[NESS] CONSTRAINTS + +SHOW REL[ATIONSHIP] KEY CONSTRAINTS + +SHOW KEY CONSTRAINTS +---- +a| + +Added filtering for the new constraint types to `SHOW CONSTRAINTS`. +Includes filtering for the node part, relationship part, or both parts of each type (`NODE KEY` filtering already exists previously). + +The existing `UNIQUENESS` filter will now return both node and relationship property uniqueness constraints. + |=== [[cypher-deprecations-additions-removals-5.6]] @@ -164,32 +201,6 @@ RETURN 'val' as one, 'val' as two [[cypher-deprecations-additions-removals-5.3]] == Version 5.3 -// TODO: Re-add this part in whatever version (not 5.3...) the relationship key and uniqueness constraints are added back in -//// -=== Deprecated features - -[cols="2", options="header"] -|=== -| Feature -| Details - -a| -//not sure what category this should be, it is more information about a coming breaking change than actual deprecation -label:returnValues[] -label:deprecated[] -[source, cypher, role="noheader"] ----- -SHOW NODE UNIQUENESS CONSTRAINTS YIELD type ----- -a| - -The current constraint type for node property uniqueness constraints, `UNIQUENESS`, will be updated to `NODE_UNIQUENESS` in Neo4j version 6.0. - -This will also be reflected in updates to some error messages and query statistics. - -|=== -//// - === Updated features [cols="2", options="header"] @@ -252,53 +263,6 @@ The property uniqueness constraint type filter now allow both `UNIQUE` and `UNIQ |=== -// TODO: Re-add this part in whatever version (not 5.3...) the relationship key and uniqueness constraints are added back in -//// -=== New features - -[cols="2", options="header"] -|=== -| Feature -| Details - -a| -label:functionality[] -label:new[] -[source, cypher, role="noheader"] ----- -CREATE CONSTRAINT name FOR ()-[r:TYPE]-() REQUIRE r.prop IS UNIQUE - -CREATE CONSTRAINT name FOR ()-[r:TYPE]-() REQUIRE r.prop IS RELATIONSHIP KEY ----- -a| - -Added relationship xref:constraints/syntax.adoc#constraints-syntax-create-rel-key[key] and xref:constraints/syntax.adoc#constraints-syntax-create-rel-unique[uniqueness] constraints. - -a| -label:functionality[] -label:new[] -[source, cypher, role="noheader"] ----- -SHOW NODE UNIQUE[NESS] CONSTRAINTS - -SHOW REL[ATIONSHIP] UNIQUE[NESS] CONSTRAINTS - -SHOW UNIQUE[NESS] CONSTRAINTS - -SHOW REL[ATIONSHIP] KEY CONSTRAINTS - -SHOW KEY CONSTRAINTS ----- -a| - -Added filtering for the new constraint types to `SHOW CONSTRAINTS`. -Includes filtering for the node part, relationship part, or both parts of each type (`NODE KEY` filtering already exists previously). - -The existing `UNIQUENESS` filter will now return both node and relationship property uniqueness constraints. - -|=== -//// - [[cypher-deprecations-additions-removals-5.2]] == Version 5.2 diff --git a/modules/ROOT/pages/execution-plans/operators.adoc b/modules/ROOT/pages/execution-plans/operators.adoc index 87596dcec..b003ac84a 100644 --- a/modules/ROOT/pages/execution-plans/operators.adoc +++ b/modules/ROOT/pages/execution-plans/operators.adoc @@ -5023,9 +5023,7 @@ This constraint can have any of the available constraint types: * Property uniqueness constraints * Property existence constraints label:enterprise-edition[] -* Node key constraints label:enterprise-edition[] -// TODO: Switch the row above to the one below when adding back relationship key and uniqueness constraints -//* Node or relationship key constraints label:enterprise-edition[] +* Node or relationship key constraints label:enterprise-edition[] The following query will create a property uniqueness constraint with the name `uniqueness` on the `name` property of nodes with the `Country` label. diff --git a/modules/ROOT/pages/introduction/cypher_neo4j.adoc b/modules/ROOT/pages/introduction/cypher_neo4j.adoc index 02a0ba62a..10ee3b16f 100644 --- a/modules/ROOT/pages/introduction/cypher_neo4j.adoc +++ b/modules/ROOT/pages/introduction/cypher_neo4j.adoc @@ -32,22 +32,12 @@ a| All constraints: xref::constraints/examples.adoc#constraints-examples-node-property-existence[node existence constraints], xref::constraints/examples.adoc#constraints-examples-relationship-property-existence[relationship existence constraints], -xref::constraints/examples.adoc#constraints-examples-node-uniqueness[node property uniqueness constraints], and -xref::constraints/examples.adoc#constraints-examples-node-key[node key constraints]. -//// -TODO: Switch the part above to the one below when adding back relationship key and uniqueness constraints -All constraints: -xref::constraints/examples.adoc#constraints-examples-node-property-existence[node existence constraints], -xref::constraints/examples.adoc#constraints-examples-relationship-property-existence[relationship existence constraints], xref::constraints/examples.adoc#constraints-examples-node-uniqueness[node property uniqueness constraints], xref::constraints/examples.adoc#constraints-examples-relationship-uniqueness[relationship property uniqueness constraints], xref::constraints/examples.adoc#constraints-examples-node-key[node key constraints], and xref::constraints/examples.adoc#constraints-examples-relationship-key[relationship key constraints]. -//// a| -Only xref::constraints/examples.adoc#constraints-examples-node-uniqueness[node property uniqueness constraints]. -// TODO: Switch the row above to the one below when adding back relationship key and uniqueness constraints -//Only xref::constraints/examples.adoc#constraints-examples-node-uniqueness[node] and xref::constraints/examples.adoc#constraints-examples-relationship-uniqueness[relationship] property uniqueness constraints. +Only xref::constraints/examples.adoc#constraints-examples-node-uniqueness[node] and xref::constraints/examples.adoc#constraints-examples-relationship-uniqueness[relationship] property uniqueness constraints. |=== diff --git a/modules/ROOT/pages/introduction/neo4j-databases-graphs.adoc b/modules/ROOT/pages/introduction/neo4j-databases-graphs.adoc index 5432dbbca..3cda77131 100644 --- a/modules/ROOT/pages/introduction/neo4j-databases-graphs.adoc +++ b/modules/ROOT/pages/introduction/neo4j-databases-graphs.adoc @@ -78,22 +78,12 @@ a| All constraints: xref::constraints/examples.adoc#constraints-examples-node-property-existence[node existence constraints], xref::constraints/examples.adoc#constraints-examples-relationship-property-existence[relationship existence constraints], -xref::constraints/examples.adoc#constraints-examples-node-uniqueness[node property uniqueness constraints], and -xref::constraints/examples.adoc#constraints-examples-node-key[node key constraints]. -//// -TODO: Switch the part above to the one below when adding back relationship key and uniqueness constraints -All constraints: -xref::constraints/examples.adoc#constraints-examples-node-property-existence[node existence constraints], -xref::constraints/examples.adoc#constraints-examples-relationship-property-existence[relationship existence constraints], xref::constraints/examples.adoc#constraints-examples-node-uniqueness[node property uniqueness constraints], xref::constraints/examples.adoc#constraints-examples-relationship-uniqueness[relationship property uniqueness constraints], xref::constraints/examples.adoc#constraints-examples-node-key[node key constraints], and xref::constraints/examples.adoc#constraints-examples-relationship-key[relationship key constraints]. -//// a| -Only xref::constraints/examples.adoc#constraints-examples-node-uniqueness[node property uniqueness constraints]. -// TODO: Switch the row above to the one below when adding back relationship key and uniqueness constraints -//Only xref::constraints/examples.adoc#constraints-examples-node-uniqueness[node] and xref::constraints/examples.adoc#constraints-examples-relationship-uniqueness[relationship] property uniqueness constraints. +Only xref::constraints/examples.adoc#constraints-examples-node-uniqueness[node] and xref::constraints/examples.adoc#constraints-examples-relationship-uniqueness[relationship] property uniqueness constraints. |=== diff --git a/modules/ROOT/pages/keyword-glossary.adoc b/modules/ROOT/pages/keyword-glossary.adoc index 87aeb309b..ba53431d4 100644 --- a/modules/ROOT/pages/keyword-glossary.adoc +++ b/modules/ROOT/pages/keyword-glossary.adoc @@ -54,19 +54,17 @@ Typically used when modifying or importing large amounts of data. | Schema | Create a constraint that ensures all nodes with a particular label have all the specified properties and that the combination of property values is unique; i.e. ensures existence and uniqueness. -// TODO: Re-add this part when adding back relationship key and uniqueness constraints -//| xref::constraints/syntax.adoc#constraints-syntax-create-rel-key[CREATE CONSTRAINT [rel_key\] [IF NOT EXISTS\] FOR ()-"["r:REL_TYPE"\]"-() REQUIRE (r.prop1[, ..., r.propN\]) IS [REL[ATIONSHIP\]\] KEY [OPTIONS {optionKey: optionValue[, ...\]}\]] -//| Schema -//| Create a constraint that ensures all relationships with a particular type have all the specified properties and that the combination of property values is unique; i.e. ensures existence and uniqueness. +| xref::constraints/syntax.adoc#constraints-syntax-create-rel-key[CREATE CONSTRAINT [rel_key\] [IF NOT EXISTS\] FOR ()-"["r:REL_TYPE"\]"-() REQUIRE (r.prop1[, ..., r.propN\]) IS [REL[ATIONSHIP\]\] KEY [OPTIONS {optionKey: optionValue[, ...\]}\]] +| Schema +| Create a constraint that ensures all relationships with a particular type have all the specified properties and that the combination of property values is unique; i.e. ensures existence and uniqueness. | xref::constraints/syntax.adoc#constraints-syntax-create-node-unique[CREATE CONSTRAINT [uniqueness\] [IF NOT EXISTS\] FOR (n:Label) REQUIRE (n.prop1[, ..., n.propN\]) IS [NODE\] UNIQUE [OPTIONS {optionKey: optionValue[, ...\]}\]] | Schema | Create a constraint that ensures the uniqueness of the combination of node label and property values for a particular property key combination across all nodes. -// TODO: Re-add this part when adding back relationship key and uniqueness constraints -//| xref::constraints/syntax.adoc#constraints-syntax-create-rel-unique[CREATE CONSTRAINT [uniqueness\] [IF NOT EXISTS\] FOR ()-"["r:REL_TYPE"\]"-() REQUIRE (r.prop1[, ..., r.propN\]) IS [REL[ATIONSHIP\]\] UNIQUE [OPTIONS {optionKey: optionValue[, ...\]}\]] -//| Schema -//| Create a constraint that ensures the uniqueness of the combination of relationship type and property values for a particular property key combination across all relationships. +| xref::constraints/syntax.adoc#constraints-syntax-create-rel-unique[CREATE CONSTRAINT [uniqueness\] [IF NOT EXISTS\] FOR ()-"["r:REL_TYPE"\]"-() REQUIRE (r.prop1[, ..., r.propN\]) IS [REL[ATIONSHIP\]\] UNIQUE [OPTIONS {optionKey: optionValue[, ...\]}\]] +| Schema +| Create a constraint that ensures the uniqueness of the combination of relationship type and property values for a particular property key combination across all relationships. | xref::indexes-for-full-text-search.adoc[CREATE FULLTEXT INDEX [name\] [IF NOT EXISTS\] FOR (n:Label["\|" ... "\|" LabelN\]) ON EACH "[" n.property[, ..., n.propertyN\] "\]" [OPTIONS {optionKey: optionValue[, ...\]}\]] | Schema @@ -178,9 +176,7 @@ Either the pattern already exists, or it needs to be created. | Writing | Update labels on nodes and properties on nodes and relationships. -| xref::constraints/syntax.adoc#constraints-syntax-list[SHOW [ALL\|UNIQUE[NESS\]\|NODE [PROPERTY\] EXIST[ENCE\]\|REL[ATIONSHIP\] [PROPERTY\] EXIST[ENCE\]\|[PROPERTY\] EXIST[ENCE\]\|NODE KEY\] CONSTRAINT[S\]] -// TODO: Switch the row above to the one below when adding back relationship key and uniqueness constraints -//| xref::constraints/syntax.adoc#constraints-syntax-list[SHOW [ALL\|NODE UNIQUE[NESS\]\|REL[ATIONSHIP\] UNIQUE[NESS\]\|UNIQUE[NESS\]\|NODE [PROPERTY\] EXIST[ENCE\]\|REL[ATIONSHIP\] [PROPERTY\] EXIST[ENCE\]\|[PROPERTY\] EXIST[ENCE\]\|NODE KEY\|REL[ATIONSHIP\] KEY\|KEY\] CONSTRAINT[S\]] +| xref::constraints/syntax.adoc#constraints-syntax-list[SHOW [ALL\|NODE UNIQUE[NESS\]\|REL[ATIONSHIP\] UNIQUE[NESS\]\|UNIQUE[NESS\]\|NODE [PROPERTY\] EXIST[ENCE\]\|REL[ATIONSHIP\] [PROPERTY\] EXIST[ENCE\]\|[PROPERTY\] EXIST[ENCE\]\|NODE KEY\|REL[ATIONSHIP\] KEY\|KEY\] CONSTRAINT[S\]] | Schema | List constraints in the database, either all or filtered on type. From 00ff458508582e8d82d4b5d2e5a9a4d717b55d43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Wed, 5 Apr 2023 08:46:55 +0200 Subject: [PATCH 6/9] Fix SHOW SETTINGS result table with updated list of procedures (#497) --- modules/ROOT/pages/clauses/listing-settings.adoc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/ROOT/pages/clauses/listing-settings.adoc b/modules/ROOT/pages/clauses/listing-settings.adoc index 39c2f3cbc..2be19fbda 100644 --- a/modules/ROOT/pages/clauses/listing-settings.adoc +++ b/modules/ROOT/pages/clauses/listing-settings.adoc @@ -200,10 +200,14 @@ LIMIT 10 | +"WARN"+ | +"The level of middleware logging"+ -| +"dbms.cluster.discovery.type"+ +| +"dbms.cluster.discovery.resolver_type"+ | +"LIST"+ | +"Configure the discovery type used for cluster name resolution"+ +| +"dbms.cluster.discovery.type"+ +| +"LIST"+ +| +"This setting has been moved to Cluster Address Settings"+ + | +"dbms.cluster.minimum_initial_system_primaries_count"+ | +"3"+ | +"This setting has been moved to Cluster Base Settings"+ @@ -224,10 +228,6 @@ LIMIT 10 | +"1d"+ | +"The time allowed for a database on a Neo4j server to either join a cluster or form a new cluster with at least the quorum of the members available. The members are provided by `dbms.cluster.discovery.endpoints` for the system database and by the topology graph for user databases."+ -| +"dbms.cluster.raft.client.max_channels"+ -| +"8"+ -| +"The maximum number of TCP channels between two nodes to operate the raft protocol. Each database gets allocated one channel, but a single channel can be used by more than one database."+ - 3+d|Rows: 10 |=== From 1b6999a6ba1cea4610034dba8e7f4bba679b418d Mon Sep 17 00:00:00 2001 From: Pontus Melke Date: Thu, 13 Apr 2023 16:06:30 +0200 Subject: [PATCH 7/9] Add docs explaining MERGE + relationship uniqueness constraints (#507) re-opening of https://github.com/neo4j/docs-cypher/pull/460 --------- --- modules/ROOT/pages/clauses/merge.adoc | 41 +++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/modules/ROOT/pages/clauses/merge.adoc b/modules/ROOT/pages/clauses/merge.adoc index bc0d2ff14..4cd4c6066 100644 --- a/modules/ROOT/pages/clauses/merge.adoc +++ b/modules/ROOT/pages/clauses/merge.adoc @@ -415,12 +415,12 @@ This is in contrast to the example shown above in xref::clauses/merge.adoc#merge [[query-merge-using-unique-constraints]] -== Using property uniqueness constraints with `MERGE` +== Using node property uniqueness constraints with `MERGE` Cypher prevents getting conflicting results from `MERGE` when using patterns that involve property uniqueness constraints. In this case, there must be at most one node that matches that pattern. -For example, given two property uniqueness constraints on `:Person(id)` and `:Person(ssn)`, a query such as `MERGE (n:Person {id: 12, ssn: 437})` will fail, if there are two different nodes (one with `id` 12 and one with `ssn` 437), or if there is only one node with only one of the properties. +For example, given two property node uniqueness constraints on `:Person(id)` and `:Person(ssn)`, a query such as `MERGE (n:Person {id: 12, ssn: 437})` will fail, if there are two different nodes (one with `id` 12 and one with `ssn` 437), or if there is only one node with only one of the properties. In other words, there must be exactly one node that matches the pattern, or no matching nodes. Note that the following examples assume the existence of property uniqueness constraints that have been created using: @@ -433,9 +433,9 @@ CREATE CONSTRAINT FOR (n:Person) REQUIRE n.role IS UNIQUE; [[merge-merge-using-unique-constraints-creates-a-new-node-if-no-node-is-found]] -=== Merge using property uniqueness constraints creates a new node if no node is found +=== Merge node using property uniqueness constraints creates a new node if no node is found -Given the property uniqueness constraint on the `name` property for all `Person` nodes, the below query will create a new `Person` with the `name` property `'Laurence Fishburne'`. +Given the node property uniqueness constraint on the `name` property for all `Person` nodes, the below query will create a new `Person` with the `name` property `'Laurence Fishburne'`. If a `'Laurence Fishburne'` node had already existed, `MERGE` would match the existing node instead. .Query @@ -454,7 +454,7 @@ RETURN laurence.name [[merge-merge-using-unique-constraints-matches-an-existing-node]] -=== Merge using property uniqueness constraints matches an existing node +=== Merge using node property uniqueness constraints matches an existing node Given property uniqueness constraint on the `name` property for all `Person` nodes, the below query will match the pre-existing `Person` node with the `name` property `'Oliver Stone'`. @@ -526,6 +526,37 @@ While there is a matching unique `Person` node with the name `'Oliver Stone'`, t Node already exists with label `Person` and property `name` = 'Oliver Stone' ---- +[[query-merge-using-relationship-unique-constraints]] +== Using relationship property uniqueness constraints with `MERGE` + +All that has been said above about node uniqueness constraints also applies to relationship uniqueness constraints. +However, for relationship uniqueness constraints there are some additional things to consider. + +For example, if there exists a relationship uniqueness constraint on `()-[:ACTED_IN(year)]-()`, then the following query, in which not all nodes of the pattern are bound, would fail: + +.Query +[source, cypher, role=test-fail] +---- +MERGE (charlie:Person {name: 'Charlie Sheen'})-[r:ACTED_IN {year: 1987}]->(wallStreet:Movie {title: 'Wall Street'}) +RETURN charlie.name, type(r), wallStreet.title +---- + +This is due to the all-or-nothing semantics of `MERGE`, which causes the query to fail if there exists a relationship with the given `year` property but there is no match for the full pattern. +In this example, since no match was found for the pattern, `MERGE` will try to create the full pattern including a relationship with `{year: 1987}`, which will lead to constraint violation error. + +Therefore, it is advised - especially when relationship uniqueness constraints exist - to always use bound nodes in the `MERGE` pattern. +The following would, therefore, be a more appropriate composition of the query: + +.Query +[source, cypher] +---- +MATCH + (charlie:Person {name: 'Charlie Sheen'}), + (wallStreet:Movie {title: 'Wall Street'}) +MERGE (charlie)-[r:ACTED_IN {year: 1987}]->(wallStreet) +RETURN charlie.name, type(r), wallStreet.title +---- + [[merge-using-map-parameters-with-merge]] === Using map parameters with `MERGE` From d4705e21e0a433c3141227f645891179edbeb4e1 Mon Sep 17 00:00:00 2001 From: Pontus Melke Date: Thu, 13 Apr 2023 15:26:28 +0200 Subject: [PATCH 8/9] BFS doesn't have an upper bound (#508) re-opening of https://github.com/neo4j/docs-cypher/pull/461 --- modules/ROOT/pages/execution-plans/operators.adoc | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/ROOT/pages/execution-plans/operators.adoc b/modules/ROOT/pages/execution-plans/operators.adoc index b003ac84a..5cd266dbd 100644 --- a/modules/ROOT/pages/execution-plans/operators.adoc +++ b/modules/ROOT/pages/execution-plans/operators.adoc @@ -2727,7 +2727,6 @@ This is only used in cases where the individual paths are not of interest. This kind of expand is only planned when: * The individual paths are not of interest. -* The relationships have an upper bound. * The lower bound is either `0` or `1` (default). This operator guarantees that all the end nodes produced are unique. From 3744693f9b7a1fe516207dad81ba3259a77509e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jens=20Pryce-=C3=85klundh?= <112686610+JPryce-Aklundh@users.noreply.github.com> Date: Thu, 20 Apr 2023 11:56:05 +0200 Subject: [PATCH 9/9] fix broken xref --- modules/ROOT/pages/keyword-glossary.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/ROOT/pages/keyword-glossary.adoc b/modules/ROOT/pages/keyword-glossary.adoc index ba53431d4..e276f6793 100644 --- a/modules/ROOT/pages/keyword-glossary.adoc +++ b/modules/ROOT/pages/keyword-glossary.adoc @@ -1080,7 +1080,7 @@ The following commands are only executable against the `system` database: | User and role | Change the password of the user that is currently logged in. -| xref:databases.adoc#administration-databases-alter-database[ALTER DATABASE ... [IF EXISTS\] [SET ACCESS {READ ONLY \| READ WRITE}\] [SET TOPOLOGY n PRIMAR{Y\|IES} [m SECONDAR{Y\|IES}\]\] [WAIT [n [SEC[OND[S\]\]\]\]\|NOWAIT\]] +| xref:administration/databases.adoc#administration-databases-alter-database[ALTER DATABASE ... [IF EXISTS\] [SET ACCESS {READ ONLY \| READ WRITE}\] [SET TOPOLOGY n PRIMAR{Y\|IES} [m SECONDAR{Y\|IES}\]\] [WAIT [n [SEC[OND[S\]\]\]\]\|NOWAIT\]] | Database | Modifies the database access mode and / or topology.