Create unique relationship based on relationship attribute - neo4j

Just like we can create a unique constraint on a "Node" attribute, can i create a unique constraint on a "Relationship" attribute. In my system every relationship has a unique "name" attribute, i want to enforce it in neo4j.
Thank you
Utpal

Sorry, there is no support for unique constraints on relationships in neo4j 3.0.x, and nothing in the 3.1 beta documentation. Relationships can have existence constraints (for neo4j enterprise), but no unique constraints.
The best you can do is ensure you're always using MERGE when creating your relationships and that the name attribute is present for that MERGE.

Related

Core Data Unique constraint except for the default value

I have an entity called "Person". it has an attribute "id" with a default value = 0. I have set a constraint in "Person" to have only unique Ids. I am loading a list of Persons from the server and storing them locally using core data. The Person ids should be unique, but when I create multiple persons locally I want the uniqueness of id to be ignored if it has the default value 0.
I just want the uniqueness constraint to work on every id different then 0, how can I do this?
thanks,
Core Data's uniqueness constraints are just that-- they require uniqueness, without exceptions. Your situation of wanting "unique except for one value that can be duplicated" isn't directly supported by Core Data. You'd have to maintain that in your own code somehow. That probably means implementing your own update-or-insert logic to check whether an ID exists. That would be something like,
Do a fetch with the specific ID.
If you find an object update it.
If you don't find an object, create a new one.
Before constraints where add to core-data the only way to insure uniqueness is to do a fetch and then if there are no results create the object. It is not that difficult to do. Enforce uniqueness in you code and use whatever custom logic you need. Try to organize you code so that there are only one or two ways to create a person so the logic is easier to handle.

How to disable auto increment Identifier (id) of the neo4j?

I'm working with two relational and non relational banks. I need the relational IDs to be attributes for nodes in the non relational database, but Neo4j does not allow the generation of these attributes.
You can't disable the internal Neo4j id, that's necessary for Neo4j to run properly.
What you can do is introduce your own id field (id is a valid property you could use, as the internal neo4j id does not use the id field) and add an index (or unique constraint, if needed).

Subgraph constraint in neo4j

Is it possible to add constraints on subgraphs? I have a tree type structure of items belonging to a category:
(cat:Category)<-[:OF_TYPE]-(item:Item {name:'foo'})
I want the name of each item that shares the same category to be unique, but item nodes of a different category should be able to have the same name. Can this be enforced with constraints?
Unfortunately currently there is no such functionality available in Neo4j.
You can only create contraints for whole database.
Alternatives:
Extension
You can create unmanaged extension that will register TransactionEventHandler. This one will be responsible for checking your specific domain constraints and reject invalid transactions.
Domain
You can alter your domain to make this available. For example - add DogCategoryItem label to each item under "dog" category. And then add separate constraint to DogCategoryItem only.
Note: I am not sure is it good or bad idead to have a lot of constraints in database (but my guess - nothing terrible should happen).
As FylmTM mentioned, this is not possible out of the box. However you can achieve this easily by having a compound property being a concatenation of the Category name and the Item name.
For example you can add a reference property on the Item node which should be unique for category name + item name concatenation
CREATE CONSTRAINT ON (i:Item) ASSERT i.reference IS UNIQUE
When you create an Item, you need to create this reference property value. As you will match anyway the Category node for creating the relationship, this is not a big deal :
MATCH (c:Category {name:"Category1"})
CREATE (i:Item {name:"Item1"})
SET i.reference = c.name + i.name
MERGE (i)-[:OF_TYPE]->(c)
If you try to create another Item with the same name in the same category, it will fails due to the Unique Constraint

Why entity cannot have uniqueness constraints with to-one mandatory inverse relationship?

Why entity cannot have uniqueness constraints with to-one mandatory inverse relationship?
Having two entities:
Person
property: name
relationship: department (to-one, non-optional)
Department
property: title (unique constraint)
relationship: person (to-many, optional)
Model won't compile in iOS 9, XCode 7.0.1 with misconfigured entity error:
Misconfigured Entity: Entity Department cannot have uniqueness
constraints and to-one mandatory inverse relationship
Person.department
Update:
Question is still relevant in XCode 8.3.1.
Short answer:
The underlying problem is most likely caused by the sqlite standard. I'm not sure about that. How ever, it's very likely that it is because of the limitations of sqlite. I found some posts on the internet, where people had issues with multiple constraints on one table and thats most likely the reason why the two-table workaround works.
Long answer:
It's pretty late, but I hope it helps anyway.
This occurs when your Entity has an unique constraint and a mandatory relation. I guess it's because of the added unique constraint behaviors in iOS 9.0. However you can solve this in two ways:
You remove the unique constraint or make the relation optional. You could handle an optional relation in code. But it won't be a nice solution.
OR
You can use a workaround. You can have both. You can create a super class having a unique constraint. However this won't work without problems, too.
Let's you have three entities. A, B and C.
A is your super class and B is a sub class of A and C is a sub class of A, too. A has an unique constraint on it's property primaryKey. When saving instances of B and C, you can not have a B and C with the same primaryKey. Because CoreData will manage both as A.
You could change A to have two Properties:
int: originalPrimaryKey (NO unique constraint)
string: primaryKey (unique constraint)
You can now map your primaryKeys to originalPrimaryKey and when setting the originalPrimaryKey you could set the string primaryKey property to CLASS_NAME.{originalPrimaryKey}. This would allow you to have the behavior, you would expect. But you have to add a workaround for primaryKeys.
If you are trying to add constraints with existing entity with records ,
The solution is
1. delete all records from existing entity
2. delete existing relationships with the entity .
3. Regenerate the +CoreDataClass and +CoreDataProperties agin.
Make your relationship properties "optional". That fixed this problem in my case.

Relating an entity to a relationship proper in Neo4j?

I'm attempting to use Neo4j to model the relationship between projects, staff, and project roles. Each project has a role called "project manager" and a role called "director". What I'm trying to accomplish in the data model is the ability to say "for project A, the director is staff X." For my purposes, it's important that "project", "staff", and "role" are all entities (as opposed to properties). Is this possible in Neo4j? In simpler terms, are associative entities possible in Neo4j? In MySQL, this would be represented with a junction table with a unique id column and three foreign key columns, one for project, staff, and role respectively, which would allow me to identify the relationship between those entities as an entity itself. Thoughts?
#wassgren's answer is a solid one, worth considering.
I'll offer one additional option. That is, you can "Reify" that relationship. Reificiation is sort of when you take a relationship and turn it into a node. You're taking an abstract association (relationship between staff and project) and your'e turning it into a concrete entity (a Role) All of the other answer options involve basically two nodes Project and Staff, with variations on relationships between them. These approaches do not reify role, but store it as a property, or a label, of a relationship.
(director:Staff {name: "Joe"})-[:plays]->(r:Role {label:"Director"})-[:member_of]->(p:Project { name: "Project X"});
So...people don't contribute to projects directly, roles do. And people play roles. Which makes an intuitive sense.
The advantages of this approach is that you get to treat the "Role" as a first-class citizen, and assert relationships and properties about it. If you don't split the "Role" out into a separate node, you won't be able to hang relationships off of the node. Further, if you add extra properties to a relationship that is masquerading as a role, you might end up with confusions about when a property applies to the role, and when it applies to the association between a staff member and a project.
Want to know who is on a project? That's just:
MATCH (p:Project {label: "Project X"})<-[:member_of]-(r:Role)<-[:plays]-(s:Staff)
RETURN s;
So I think what I'm suggesting is more flexible for the long term, but it might also be overkill for you.
Consider a hypothetical future requirement: we want to associate roles with a technical level or job category. I.e. the project manager should always be a VP or higher (silly example). If your role is a relationship, you can't do that. If your role is a proper node, you can.
Conceptually, a Neo4j graph is built based on two main types - nodes and relationships. Nodes can be connected with relationships. However, both nodes and relationships can have properties.
To connect the Project and Staff nodes, the following Cypher statement can be used:
CREATE (p:Project {name:"Project X"})-[:IS_DIRECTOR]->(director:Staff {firstName:"Jane"})
This creates two nodes. The project node has a Label of type Project and the staff node has a Label of type Staff. Between these node there is a relationhip of type IS_DIRECTOR which indicates that Jane is the director of the project. Note that a relationship is always directed.
So, to find all directors of all project the following can be used:
MATCH (p:Project)-[:IS_DIRECTOR]->(director:Staff) RETURN director
The other approach is to add properties to a more general relationship type:
create (p:Project {name:"Project X"})<-[:MEMBER_OF {role:"Director"}]-(director:Staff {firstName:"Jane"})
This shows how you can add properties to a relationship. Notice that the direction of the relationship was changed for the second example.
To find all directors using the property based relationship the following can be used:
MATCH (p:Project)<-[:MEMBER_OF {role:"Director"}]-(directors:Staff) RETURN directors
To retrieve all role types (e.g. director) the following can be used:
MATCH
(p:Project)-[r]->(s:Staff)
RETURN
r, // The actual relationship
type(r), // The relationship type e.g. IS_DIRECTOR
r.role // If properties are available they can be accessed like this
And, to get a unique list of role names COLLECT and DISTINCT can be used:
MATCH
(p:Project)-[r]->(s:Staff)
RETURN
COLLECT(DISTINCT type(r)) // Distinct types
Or, for properties on the relationship:
MATCH
(p:Project)-[r]->(s:Staff)
RETURN
COLLECT(DISTINCT r.role) // The "role" property if that is used
The COLLECT returns a list result and the DISTINCT keyword makes sure that there are no duplicates in the list.

Resources