2
votes

I'm a noob Neo4j user trying to learn with Neo4j Milestone 2.0.0-M03. I'm trying to create nodes that are unique, not by the properties that they hold, but by the relationships that they have.

I create a database with:

MERGE (p:Person { name : 'Bill' })
MERGE (p:Person { name : 'Ben' })
MERGE (p:Person { name : 'Bob' })

I then create a 'Team' with members Bill and Ben:

MATCH bill:Person, ben:Person  
WHERE bill.name='Bill' AND ben.name='Ben' 
CREATE UNIQUE t:Team-[:HAS_MEMBER]->bill, t:Team-[:HAS_MEMBER]->ben

I then want to create a second team with members Bill and Bob, however doing the same as above, ie:

MATCH bill:Person, bob:Person  
WHERE bill.name='Bill' AND bob.name='Bob' 
CREATE UNIQUE t:Team-[:HAS_MEMBER]->bill, t:Team-[:HAS_MEMBER]->bob

This makes the minimal change of adding Bob to the existing team. Thus, I have one team containing Bill, Ben and Bob, but I want two teams that are unique by their members.

I appreciate that this is correct, given the semantics of 'CREATE UNIQUE'. Unfortunately, I can't figure out the correct statement to create the second team node that is uniquely identified by the members it has.

I do not wish to put a property on the teams that distinguishes them, I want the team nodes to be uniquely identified by their relationships, not their properties.

I could create a dual relationship 'OMITS_MEMBER', that is present between a team and a person if, and only if, HAS_MEMBER is not present. This seems to add an undesirable database constraint.

Given that I can express this sort of thing in the mathematics of graph theory without team properties or a dual relationship, I'm sure the clever folks developing Neo4j have a way of doing it. I'm struggling to figure it out.

3

3 Answers

1
votes

In this case, you probably should not be using CREATE UNIQUE, but rather just CREATE. If it is an existing team that you want to add members to, use CREATE UNIQUE.

0
votes

Perhaps drop unique but check whether team being created will be unique yourself? Something along those lines:

MATCH bill:Person, bob:Person
WHERE bill.name='Bill' AND bob.name='Bob' 
and not bill-[:HAS_MEMBER*2]-bob
CREATE t2:Team-[:HAS_MEMBER]->bill, t2:Team-[:HAS_MEMBER]->bob

This of course almost certainly doesn't cover all cases, and might be tricky to code

0
votes

Each team you want to have are nodes, so at some point in your program you need to keep track of these. Even if you are adamant about having teams without properties, they will still have node ID's. So the following should work:

  • Create a team and get its node ID (say it returns 5)

    CREATE (t:Team) RETURN ID(t)
    
  • Then add your members to the team

    START t=node(5)
    MATCH bill:Person, ben:Person
    WHERE bill.name='Bill' AND ben.name='Ben' 
    CREATE t-[:HAS_MEMBER]->bill, t-[:HAS_MEMBER]->ben
    

I think you could also combine these calls using the WITH statement, but I haven't tried it.