Merging a "Bidirectional" Relationship

309 views
Skip to first unread message

Ben Titmarsh

unread,
Feb 12, 2014, 6:56:32 AM2/12/14
to ne...@googlegroups.com
Hi Guys,

I am aware that Neo4J doesn't have a concept of a bidirectional relationship and I believe that's causing me a problem when using MERGE.  Here is my Cypher:

MATCH (fromCard:Card),(toCard:Card)
MERGE (fromCard:Card)-[r:DECK_INCIDENCE]->(toCard:Card)
SET r.deckCount = coalesce(r.deckCount, 0) +1

So say I have a collection of 4 cards: "Hearts","Diamonds","Clubs","Spades"

The first time I create the relationship between Hearts and Diamonds, i.e. Hearts -> Diamonds.  However, the next time the cards are in a different order and when I attempt to MERGE Diamonds -> Hearts a new relationship is created because no relationship exists in that direction.  This is not what I want, I need to increment the deckCount property on the relationship regardless of the direction and don't want to have to manage two relationships per card.

I cannot guarantee the order of cards and in essence I need to model a Bidirectional Relationship.  How can I achieve what I need using MERGE?

Cheers,
Ben.

Ben Titmarsh

unread,
Feb 12, 2014, 7:45:36 AM2/12/14
to ne...@googlegroups.com
Ah my mistake!  Didn't qualify my match with the property that I was matching on!  This works:

MATCH (fromCard:Card { name: {fromCardName}}),(toCard:Card{ name: {toCardName}})

MERGE (fromCard:Card)-[r:DECK_INCIDENCE]->(toCard:Card)
SET r.deckCount = coalesce(r.deckCount, 0) +1

Peter Neubauer

unread,
Feb 12, 2014, 7:55:19 AM2/12/14
to Neo4j User
Cool Ben.

G: neubauer.peter
S: peter.neubauer
P: +46 704 106975
L: http://www.linkedin.com/in/neubauer
T: @peterneubauer

Neo4j 2.0.0 - (graphs)-[:FOR]->(everyone)
Kids LAN creative party in Malmö - Kidscraft ICE
> --
> You received this message because you are subscribed to the Google Groups
> "Neo4j" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to neo4j+un...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.

Ben Titmarsh

unread,
Feb 20, 2014, 5:30:56 PM2/20/14
to ne...@googlegroups.com
I'd bluffed myself into thinking that I'd solved this but actually I hadn't.  This is my cypher:


MATCH (fromCard:Card { name: {fromCardName}}),(toCard:Card{ name: {toCardName}})
MERGE (fromCard:Card)-[r:DECK_INCIDENCE]->(toCard:Card)
SET r.passCount = coalesce(r.passCount, 0) +1

For each pair of cards I end up creating a relationship in both directions, for example the first time fromCard='HEARTS' and toCard='SPADES', HEARTS->SPADES is created with passCount 1, then when fromCard='SPADES' and toCard='HEARTS' SPADES->HEARTS is created with passCount 1.  The desired behaviour is that there is only one "bidirectional" relationship.  The direction is really not important, all I'm modelling is the strength of the relationship i.e. the number of times that this combination of cards is "passed" (note that I've used Hearts and Spades here purely for explanation, I in fact have ~20k domain-specific cards)

I tried without the arrow


MATCH (fromCard:Card { name: {fromCardName}}),(toCard:Card{ name: {toCardName}})
MERGE (fromCard:Card)-[r:DECK_INCIDENCE]-(toCard:Card)
SET r.passCount = coalesce(r.passCount, 0) +1

but that gives me: Only directed relationships are supported in CREATE, while MATCH allows to ignore direction.

So I'm stuck here.  It's important that relationships are created lazily, i.e. the first time a 'pass' is registered, as for may pairs of cards they will never be related at all.  So how can I use the semantics of a merge to create a relationship where the property passCount can be incremented (or coalesced if null) regardless of the direction?

Michael Hunger

unread,
Feb 20, 2014, 5:51:16 PM2/20/14
to ne...@googlegroups.com
MERGE without arrows were added and will be available in the next release.

Until then try to replace that last merge with CREATE UNIQUE

Michael

Ben Titmarsh

unread,
Feb 21, 2014, 5:30:42 AM2/21/14
to ne...@googlegroups.com
Hi Michael,

Based on your advice I changed my query to:

MATCH (fromCard:Card { name: 'Hearts'}),(toCard:Card{ name: 'Spades'})
CREATE UNIQUE (fromCard)-[r:DECK_INCIDENCE]-(toCard)
SET r.passCount = coalesce(r.passCount, 0) +1

I deleted one of the relationships and surely enough which ever order the cards are specified in it updates the relationship.

However, it doesn't create the nodes 'Hearts' and 'Spades' if they don't yet exist.  I realise that I didn't specify this in my previous post but I need the query to lazily create the nodes too, so in summary I need it to:

1) Lazily Create Nodes
2) Lazily Create Relationships
3) Increment the passCount property on the relationship whether it was just created or preexisted regardless of the direction of the relationship.

I'll certainly leverage MERGE without arrows when it's released, but in the mean time I'd really like to get something live and working.  Any guidance would be much appreciated!

Ben.

Michael Hunger

unread,
Feb 21, 2014, 8:45:14 AM2/21/14
to ne...@googlegroups.com
To lazily create the nodes use MERGE in the first line instead of MATCH
Reply all
Reply to author
Forward
0 new messages