Benedict Lewis
Benedict Lewis

Reputation: 2813

Create node and relationship if end node exists (otherwise only create first node)

I have an application which dispatches database write commands via a message queue to workers (very high volume), so there is a no guarantee as to the order they will be received in.

I have two nodes, for example, "Account" and "Media". In this hypothetic application, a user can upload media anonymous, which automatically creates an account for them which they can then associate later.

Two messages, one for Account and one for Media will be received (almost certainly by different workers). Neither of them knows whether the other has been written yet. I need to write a query which will be run on each worker, which:

Therefore, regardless of the order which each message is received in, the first query will create node A, and the second query will create node B + relationship.

If I was creating them both in the same query, it would be simple:

CREATE (m:Media { url: 'xyz.jpg' })-[:POSTED_BY]->(u:Account { username: 'johndoe' })
RETURN m,u

I've looked at CREATE UNIQUE and MERGE, however both seem to create the node if it doesn't exist, rather than just doing nothing.

Upvotes: 1

Views: 265

Answers (2)

Matt
Matt

Reputation: 3677

I know the answer is already accepted, but don't feel like it actually answers the question, to wit:

If the other node does not exist, only create the current node

This can be achieved by the following:

CREATE (m:Media { url: 'xyz.jpg' })
WITH m 
MATCH(u:Account { username: 'johndoe' }) 
CREATE(m)-[r:POSTED_BY]->(u)"
RETURN m

Unfortunately, this only returns m if the match was successful.

Upvotes: 0

Dave Bennett
Dave Bennett

Reputation: 11216

I think you want to use MERGE for this operation. Essentially, instead of creating one node at a time, you can create both nodes and the relationship but then update the particular node with additional properties.

Consider Message One is the media message

MERGE (m:Media { url: 'xyz.jpg' })
SET m =+ {media_props}
MERGE (u:Account { username: 'johndoe' })
MERGE (m)-[:POSTED_BY]->(u)
RETURN m

Consider Message Two is the new user account message

MERGE (u:Account { username: 'johndoe' })
SET u =+ {user_props}
MERGE (m:Media { url: 'xyz.jpg' })
MERGE (m)-[:POSTED_BY]->(u)
RETURN u

You could conceivably create each node separately via MERGE and have a third message for the relationship. The pattern would be the same but would not set any additional properties on either of the nodes.

For example...

// message 1
// create the media node
MERGE (m:Media { url: 'xyz.jpg' })
SET m =+ {media_props}
RETURN m


// message 2
// create the user/account node
MERGE (u:Account { username: 'johndoe' })
SET u =+ {user_props}

// message 3
// create the relationship
MERGE (u:Account { username: 'johndoe' })
MERGE (m:Media { url: 'xyz.jpg' })
MERGE (m)-[r:POSTED_BY]->(u)
RETURN m,r,u

Note that all of the solutions assume that the key for identifying the media and the account in the merge statement are unique.

Upvotes: 1

Related Questions