fdorssers
fdorssers

Reputation: 719

How to use MERGE (or something else) in neo4j to create new nodes and relationships based on info in labels in other relationships

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:

  1. User which contains the label user_id (and some other stuff), generally has nothing to do with the twitter id
  2. Social which represents a social network (for example Twitter if the name label is 'twitter').

On top of that there are two types of relationships:

  1. 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 network
  2. FOLLOWS 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:

  1. Find the user connected to Twitter with id 1111 (This one always exists)
  2. See if there is a user connected to Twitter who has an account with id 5555. If there's none then create a new one, set the Twitter relationship and set a user_id label on the node
  3. Set a FOLLOWS 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

Answers (2)

Supamiu
Supamiu

Reputation: 8731

I think you have a problem with your graph model, and that's why you are facing the actual problem.

Let me explain the problem with your model

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).

How to create a better graph model?

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: Graph Model

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

MicTech
MicTech

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

Related Questions