Navigation Menu

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Unique constraint across multiple labels #7814

Open
naraesk opened this issue Aug 26, 2016 · 13 comments
Open

Feature Request: Unique constraint across multiple labels #7814

naraesk opened this issue Aug 26, 2016 · 13 comments

Comments

@naraesk
Copy link

naraesk commented Aug 26, 2016

I have a set of nodes with multiple Labels (A, B, C). All nodes have a common property, which is unique across all labels. However, when creating unique constraint it is limited to one label, isn't it?

Documentation says something like:

CREATE CONSTRAINT ON (n:A) ASSERT n.uid IS UNIQUE

But it would be useful to do something like this:

CREATE CONSTRAINT ON (n:A AND n:B AND n:C) ASSERT n.uid IS UNIQUE

or

CREATE CONSTRAINT ON (n) ASSERT n.uid IS UNIQUE

@spacecowboy
Copy link
Contributor

Would make it easier, but at the moment you could create a common label D for all nodes and create the constraint on that.

@NickyYo
Copy link

NickyYo commented Sep 28, 2016

Hi @spacecowboy, i was re-directed to this from stack overflow as a top search on Google.
Do you have an example on how to create common labels? Struggling a little.

Many thanks, Nick.

@spacecowboy
Copy link
Contributor

@NickyYo

Ideally you can do this from the start. So that when you create nodes in the first place, they have the correct labels.

Say I have two kinds of labels originally, COWBOY and SAMURAI, and I want an index that spans both of these labels. I then define a third label, let's call it GIBSONTYPE.

A create query then looks something like this

CREATE (n:GIBSONTYPE:COWBOY {name:"Case"})

and

CREATE (n:GIBSONTYPE:SAMURAI {name: "Molly"})

Both SAMURAI nodes and COWBOY nodes have a label in common, namely GIBSONTYPE. So indices can be created on that label.

In case you need to update an existing graph, you can set new labels on nodes in this way for example:

MATCH (n:COWBOY)
SET n:COWBOY:GIBSONTYPE

and naturally

MATCH (n:SAMURAI)
SET n:SAMURAI:GIBSONTYPE

@asashour
Copy link
Contributor

Is there a real-life use case for a multi-label constraint, which could be shared with others?

@naraesk
Copy link
Author

naraesk commented May 20, 2020

The use case is the same as for any other unique constraint. The question is, do you want to create the super type D (referring to the comment of spacecowboy ) or not? In my case, you would add the label D to tens of thousands of nodes, which would not be used in any query afterwards. This makes the database more complex than it should be.

@yarduza
Copy link

yarduza commented Aug 5, 2020

I vote up the need for this.

@NielsonJ
Copy link

NielsonJ commented Nov 13, 2020

I had like to use a constrain related to uuid's across several labels.

@hadyrashwan
Copy link

hadyrashwan commented Aug 16, 2021

I don't know if that's the same or not.
let's say I have

  • company label with properties of:
    • uuid
    • name
  • employee label
    • uuid
    • name

with HAS_EMPLOYEE relationship.

I want to have a constrain that says only one employee in one each company can have name as Alice.

@armensanoyan
Copy link

Any news about this topic ? Is there chance to get a functions to add constraint for multiple labels ?

@grokpot
Copy link

grokpot commented Jul 1, 2022

I arrived here because I want to use node ID to simplify operations (e.g., "connect ID X to ID Y" regardless of labels), but then I see the warning here stating:

Neo4j reuses its internal ids when nodes and relationships are deleted. This means that applications using, and relying on internal Neo4j ids, are brittle or at risk of making mistakes. It is therefore recommended to rather use application-generated ids.

Fine - but then why can't I generate a unique constraint which either A) spans multiple labels (i.e., this issue), or B) for all nodes (does not require a label)?

Now I am required to create a uuid for each label, or a supertype for all labels.

@tntsoft
Copy link

tntsoft commented Jul 17, 2022

I've started with Neo4j yesterday and already ran into this issue. It would be very useful to add a constraint on a combination of 2 or more labels.

@Xqua
Copy link

Xqua commented Feb 23, 2023

Hey, I'm bumping this up as well
We have a lot of ontology which looks like this:

  • Github:Account
  • Github:Repository
  • Github:Issue
  • Twitter:Account
  • Twitter:Tweet

Basically, a lot of Service:Type ontologies.

Yes we can add a label that is ServiceType but it feels very messy to me to add it just for constraints, and never use it again. And we need to do queries like MATCH (:Account) to get the services

I would love to be able to add constraints to label combos. Right now we are handling it by being very careful with our ingests and making sure we don't end up with duplicates, but that's not the best...

@burqen
Copy link
Contributor

burqen commented Feb 28, 2023

Hello everyone. Let me give a (much delayed) update on this topic.

There are no concrete plans to prioritise this work currently, although multi-label constraints are recognised as something that would be useful and something that we would like to investigate in more detail at some point.

For now, the suggestion from @spacecowboy is the way to work around this issue.

Let me also comment on some specific things below.


Uniqueness across entity types

A comment on the requirement to have unique UUID across all different entities in the database. In most cases the required uniqueness applies to each type specifically and not across the types, even if they use the same property. E.g. Company and Person. Let's say we use UUID to uniquely reference both companies and persons. Both of them will have the UUID property, but when we look for a company we know that we are looking for a company. We will not mistake a person for a company simply because they model very different things. Since we will include the label in our query, MATCH (c:Company {UUID:x} RETURN c, we don't really case if some person node also have the same UUID as our company, simply because they will never mix.

Now, there are of course cases where the uniqueness constraint applies across labels, e.g, we have Student and Teacher nodes and we want to identify a person uniquely by the UUID. In this case we will need the extra Person label to indicate that student and teacher nodes have a common super type.


@hadyrashwan

I don't know if that's the same or not.
let's say I have
company label with properties of:
-uuid
-name
employee label
-uuid
-name
with HAS_EMPLOYEE relationship.
I want to have a constrain that says only one employee in one each company can have name as Alice.

What you are referring to we could call "neighbourhood constraints", "node centric constraints", "local constraints" or similar, and although it is an interesting topic it is different from what this issue is about.


@Xqua

We have a lot of ontology which looks like this:

Github:Account
Github:Repository
Github:Issue
Twitter:Account
Twitter:Tweet
Basically, a lot of Service:Type ontologies.

Yes we can add a label that is ServiceType but it feels very messy to me to add it just for constraints, and never use it again. And we need to do queries like MATCH (:Account) to get the services

I would love to be able to add constraints to label combos. Right now we are handling it by being very careful with our ingests and making sure we don't end up with duplicates, but that's not the best...

If you have a property that needs to be unique across all of those different type of nodes, then currently there is no other way than to give them a common label.

Since you need to get all of the services separately I would refactor them into their own nodes instead of inlining them into each specific account, repository, etc. This will make your modell cleaner and easier to work with I think. Something like:

// Each service has it's own node
CREATE (github:Service {name:"Github"})
CREATE (twitter:Service {name:"Twitter"})

// Each specific instance of account, repository, issue, tweet, etc belong to a specific service
CREATE (exampleAccount:Account {...})-[:BELONG_TO]->(github)
CREATE (exampleTweet:Tweet {...})-[:BELONG_TO]->(twitter)
// ... and so on

Getting all of your services is now as simple as

MATCH (service:Service) RETURN service;

and getting, e.g, all twitter accounts

MATCH (account:Account)-[:BELONG_TO]->(:Service {name:"Twitter"}) RETURN account;

You can find more modelling tips here https://neo4j.com/docs/getting-started/current/data-modeling/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.