Reputation: 451
I have the following labels:
(:Product)
(:Brand)
Their relationships is as follows:
(:Product)-[:is_of]->(:Brand)
As an example, if the below query is run twice it will succeed.
CREATE (:Product { name: "Chocolate"})-[:is_of]->(:Brand {name: "Cadbury"})
And the graph result for the below query can be seen in the image here
MATCH (p:Product { name: "Chocolate"})-[:is_of]->(b:Brand {name: "Cadbury"}) RETURN p,b
As you can see there is 2 "Chocolate" product nodes and 2 "Cadbury" brand nodes.
I would like to enforce that when creating a product there is only one product node with property name = "Chocolate"
that has an is_of
relationship with a brand with property name = "Cadbury"
. So the above CREATE
query would fail on the second attempt with some message like: There is already one product node with a name = "Chocolate" and a brand of "Cadbury". This is prohibited by a constraint
.
The relational database analog would be a primary key that stretches over multiple foreign keys. For example, adding the below to table Product
where table Brand
has a primary key Brand ID
:
PRIMARY KEY("Product ID","Brand ID")
I've tried placing a constraint on a property of the Brand to only allow unique brands. But the problem is you can still create two products that is_of
the same brand. I don't want to create a unique constraint on product name
as well because there can be multiple "Chocolate" products from different brands.
I've read through the documentation but it seems that constraints can only be placed on properties...
I would imagine syntax that would look something like below:
CREATE CONSTRAINT ON g=(p:Product)-[:is_of]->(b:Brand) ASSERT g IS UNIQUE FOR p.name, b.name
Upvotes: 2
Views: 1444
Reputation: 77
Adding an update to this older thread as this comes up with constraint search results.
What you're trying to do requires an Enterprise license. You can enforce constraints on paths ()-[]-() when you have an enterprise license. You can also use scenarios with multiple attributes.
As an FYI, I would turn your arrows the other way as IMHO brands have a relationship (directed) to their products. It might enable the constraint to be enforced with the non-enterprise version a bit easier as well. Just a thought.
Upvotes: 0
Reputation: 33175
The short answer is No.
There has been talk about having arbitrary pattern syntax for constraints in Neo, but it's not there or on the roadmap as of yet, AFIAK. The closest I've found in the wild is in an unmerged CIP in an unofficial repo:
https://github.com/Mats-SX/openCypher/blob/88c0f11f11410ce2f68dc050e54ff419058c6cad/cip/1.accepted/CIP2016-12-14-Constraint-syntax.adoc
See documentation for current available constraint syntax:
https://neo4j.com/docs/developer-manual/current/cypher/schema/constraints/
The closest you can come in 3.3.x, I think, is converting that :is_of
relationship to a node and putting properties on it that you can make a node key with.
Upvotes: 1
Reputation: 16375
Maybe you can try using MERGE
instead of CREATE
. The docs about MERGE
says:
The MERGE clause ensures that a pattern exists in the graph. Either the pattern already exists, or it needs to be created.
So running the following Cypher command twice
MERGE (:Product { name: "Chocolate"})-[:is_of]->(:Brand {name: "Cadbury"});
will produce the following graph:
Upvotes: 1