Reputation: 719
So basically I'm trying to create relationships in a network, based on information that is in other relationships. I've added an example to demonstrate what I'd like to achieve.
In this example I'm tracking users who have twitter accounts. There are two types of nodes:
User
which contains the label user_id
(and some other stuff), generally has nothing to do with the twitter idSocial
which represents a social network (for example Twitter if the name
label is 'twitter').On top of that there are two types of relationships:
ACCOUNT
which connects User
to Social
to denote whether someone has an account, this relationship also has the label name
to represent the specific ID or name on that social networkFOLLOWS
which can connect one User
(u1
) to another User
(u2
) if u1
follows u2
on Twitter.The following three lines create three users with user_id
1 through 3 who all have a Twitter account, including the specific twitter id.
MERGE (u:User {user_id:'1', other_stuff:'...'}) MERGE (s:Social {name:'twitter'}) MERGE (u)-[:ACCOUNT {name:1111}]->(s)
MERGE (u:User {user_id:'2', other_stuff:'...'}) MERGE (s:Social {name:'twitter'}) MERGE (u)-[:ACCOUNT {name:2222}]->(s)
MERGE (u:User {user_id:'3', other_stuff:'...'}) MERGE (s:Social {name:'twitter'}) MERGE (u)-[:ACCOUNT {name:3333}]->(s)
So now I have a new piece of information: The person with twitter id 1111
follows another person with twitter id 5555
.
So what has to happen:
1111
(This one always exists)5555
. If there's none then create a new one, set the Twitter relationship and set a user_id
label on the nodeFOLLOWS
relationship to indicate that 1111
is following 5555
Initially I had the following cypher statment:
// Try to match against existing user node, or create new
MERGE (u1:User {user_id:'t5555'})
// Try to match against existing social node, or create new
MERGE (s:Social {name:'twitter'})
// Try to match against a user who has a twitter account '1111'
MERGE (u2:User)-[:Account {name:1111}]->(s)
// Try to add account for new user 5555
MERGE (u1)-[:Account {name:'5555'}]->(s)
// Try to find `FOLLOWS` relationship
MERGE (u2)-[:FOLLOWS]->(u1)
But that didn't really work right. I realized that I'm matching against user_id
while I should only be matching against twitter account names in relationships.
A more recent try is the following:
MERGE (u1:User)-[:ACCOUNT {name:1111}]->(s1:Social {name:'twitter'})
MERGE (u2:User)-[:ACCOUNT {name:5555}]->(s2:Social {name:'twitter'})
MERGE (u1)-[:FOLLOWS]-(u2)
This does add a new node for the user u2
(though without user_id atm), but it also creates a new Social
node. I sort of get why due to what is explained here, but there they assume that there is a label on the actual node to match against.
So what would be the right way to do this? Ideally in a way that I can always use the same statement. For example that after adding the fact that 1111
is following 5555
I can also add that 2222
is following 5555
without creating any unnecessary new nodes.
Upvotes: 1
Views: 629
Reputation: 8731
I think you have a problem with your graph model, and that's why you are facing the actual problem.
How can you say if User a likes User b on facebook? you can't create a relationship pointing to another relationship, if you point to the user, you'll have to specify which social account the user is liking (adding a property in the relation).
In fact, I think your mistake here is to store the account as a relationship, where you have to store it as a node.
Here is a basic drawing for a good graph model in your case:
Using a model like this, you can have a User related to multiple accounts, and liking other user's account (You can add a timestamp property in the LIKE
relation if needed using timestamp() method).
Also, you can add more informations 'around accounts (twitter profile description, facebook banner uri, etc...)
Upvotes: 2
Reputation: 45083
You need to set UNIQUE constraint on those properties.
e.g.
CREATE CONSTRAINT ON (user:User) ASSERT user.user_id IS UNIQUE
http://neo4j.com/docs/stable/query-constraints.html
Upvotes: 2