Skip to content

Commit 3103ad4

Browse files
authored
Add docs explaining MERGE + relationship uniqueness constraints (#507)
re-opening of #460 ---------
1 parent 22711ef commit 3103ad4

File tree

1 file changed

+36
-5
lines changed

1 file changed

+36
-5
lines changed

modules/ROOT/pages/clauses/merge.adoc

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -415,12 +415,12 @@ This is in contrast to the example shown above in xref::clauses/merge.adoc#merge
415415

416416

417417
[[query-merge-using-unique-constraints]]
418-
== Using property uniqueness constraints with `MERGE`
418+
== Using node property uniqueness constraints with `MERGE`
419419

420420
Cypher prevents getting conflicting results from `MERGE` when using patterns that involve property uniqueness constraints.
421421
In this case, there must be at most one node that matches that pattern.
422422

423-
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.
423+
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.
424424
In other words, there must be exactly one node that matches the pattern, or no matching nodes.
425425

426426
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;
433433

434434

435435
[[merge-merge-using-unique-constraints-creates-a-new-node-if-no-node-is-found]]
436-
=== Merge using property uniqueness constraints creates a new node if no node is found
436+
=== Merge node using property uniqueness constraints creates a new node if no node is found
437437

438-
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'`.
438+
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'`.
439439
If a `'Laurence Fishburne'` node had already existed, `MERGE` would match the existing node instead.
440440

441441
.Query
@@ -454,7 +454,7 @@ RETURN laurence.name
454454

455455

456456
[[merge-merge-using-unique-constraints-matches-an-existing-node]]
457-
=== Merge using property uniqueness constraints matches an existing node
457+
=== Merge using node property uniqueness constraints matches an existing node
458458

459459
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'`.
460460

@@ -526,6 +526,37 @@ While there is a matching unique `Person` node with the name `'Oliver Stone'`, t
526526
Node already exists with label `Person` and property `name` = 'Oliver Stone'
527527
----
528528

529+
[[query-merge-using-relationship-unique-constraints]]
530+
== Using relationship property uniqueness constraints with `MERGE`
531+
532+
All that has been said above about node uniqueness constraints also applies to relationship uniqueness constraints.
533+
However, for relationship uniqueness constraints there are some additional things to consider.
534+
535+
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:
536+
537+
.Query
538+
[source, cypher, role=test-fail]
539+
----
540+
MERGE (charlie:Person {name: 'Charlie Sheen'})-[r:ACTED_IN {year: 1987}]->(wallStreet:Movie {title: 'Wall Street'})
541+
RETURN charlie.name, type(r), wallStreet.title
542+
----
543+
544+
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.
545+
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.
546+
547+
Therefore, it is advised - especially when relationship uniqueness constraints exist - to always use bound nodes in the `MERGE` pattern.
548+
The following would, therefore, be a more appropriate composition of the query:
549+
550+
.Query
551+
[source, cypher]
552+
----
553+
MATCH
554+
(charlie:Person {name: 'Charlie Sheen'}),
555+
(wallStreet:Movie {title: 'Wall Street'})
556+
MERGE (charlie)-[r:ACTED_IN {year: 1987}]->(wallStreet)
557+
RETURN charlie.name, type(r), wallStreet.title
558+
----
559+
529560
[[merge-using-map-parameters-with-merge]]
530561
=== Using map parameters with `MERGE`
531562

0 commit comments

Comments
 (0)