0
votes

I have a linked list of replies off of a Post that looks like this:

enter image description here

With the "first" reply in the list having a NEWEST_REPLY relationship to Post and subsequent replies having a NEXT_REPLY relationship. The query to get the above graph:

MATCH (p:Post {id: $postId})-[:NEWEST_REPLY|NEXT_REPLY*]->(r:Reply) 
return p, r

I want to create a cypher query that either

  1. Creates a reply and creates the NEWEST_REPLY relationship when there are no replies OR
  2. Creates a reply, deletes the current NEWEST_REPLY relationship, creates a NEXT_REPLY relationship to the previous NEWEST_REPLY and a NEWEST_REPLY relationship to the new Reply.

This statement:

MATCH (p:Post {id: $postId})-[rel:NEWEST_REPLY]->(previousNewestReply:Reply)
DELETE rel
CREATE (r:Reply { id: apoc.create.uuid(), body: $body, createdAt: datetime(), updatedAt: datetime() })
WITH r, p, previousNewestReply
MATCH (u:User)
WHERE u.id = $userId 
CREATE (r)<-[:WROTE]-(u)
CREATE (r)<-[:NEWEST_REPLY]-(p)
CREATE (r)-[:NEXT_REPLY]->(previousNewestReply)
RETURN u, p

achieves number 2.

What I now need to do is conditionally run this statement if the rel in MATCH (p:Post {id: $postId})-[rel:NEWEST_REPLY]->(previousNewestReply:Reply) exists, but if it does not exist, just create NEWEST_REPLY for the first time as well as creating the reply and the User-[:WROTE]->Reply relationship. I'm new to cypher and digging into MERGE, CASE, predicate functions and apoc.when() and not sure which would be the simplest and most appropriate.

Here's an attempt at using CASE:

MATCH (p:Post {id: "db7ee38c-fe60-430e-a7c7-0b2514401343"})
RETURN
CASE EXISTS( (p)-[rel:NEWEST_REPLY]->(replies:Reply) )
WHEN true  THEN DELETE rel CREATE (r:Reply { id: apoc.create.uuid(), body: "new with CASE1", createdAt: datetime(), updatedAt: datetime() }) WITH r, p, replies MATCH (u:User) WHERE u.id = "e14d409e-d970-4c5c-9cc7-3b224c774835" CREATE (r)<-[:WROTE]-(u) CREATE (r)<-[:NEWEST_REPLY]-(p) CREATE (r)-[:NEXT_REPLY]->(replies)
WHEN false THEN CREATE (r:Reply { id: apoc.create.uuid(), body: "new with CASE2", createdAt: datetime(), updatedAt: datetime() }) WITH r, p, previousNewestReply MATCH (u:User) WHERE u.id = "e14d409e-d970-4c5c-9cc7-3b224c774835" CREATE (r)<-[:WROTE]-(u) CREATE (r)<-[:NEWEST_REPLY]-(p) END
AS result;

And running into the following SyntaxError:

Invalid input 'r': expected whitespace, comment, '{', node labels, MapLiteral, a parameter, a parameter (old syntax), a relationship pattern, '(', '.', '[', '^', '*', '/', '%', '+', '-', "=~", IN, STARTS, ENDS, CONTAINS, IS, '=', '~', "<>", "!=", '<', '>', "<=", ">=", AND, XOR, OR, WHEN, ELSE or END (line 4, column 24 (offset: 145))
"WHEN true  THEN DELETE rel CREATE (r:Reply { id: apoc.create.uuid(), body: "new with CASE1", createdAt: datetime(), updatedAt: datetime() }) WITH r, p, replies MATCH (u:User) WHERE u.id = "e14d409e-d970-4c5c-9cc7-3b224c774835" CREATE (r)<-[:WROTE]-(u) CREATE (r)<-[:NEWEST_REPLY]-(p) CREATE (r)-[:NEXT_REPLY]->(replies)"

My sense is that the logic I am attempting in either THEN statements is too complex for a CASE. Is there a more appropriate with to essentially do an if/else off of whether or not the NEWEST_REPLY relationship exists off of a specific Post?

2

2 Answers

1
votes

[UPDATED]

This query should work for you:

MATCH (p:Post), (u:User)
WHERE p.id = $postId AND u.id = $userId
OPTIONAL MATCH (p)-[rel:NEWEST_REPLY]->(prevNewest:Reply)
CREATE (u)-[:WROTE]->(r:Reply {id: apoc.create.uuid(), body: "foo", createdAt: datetime(), updatedAt: datetime()})<-[:NEWEST_REPLY]-(p)
FOREACH(_ IN CASE WHEN rel IS NOT NULL THEN [1] END | DELETE rel CREATE (r)-[:NEXT_REPLY]->(prevNewest))

I asssume postId and userId are passed as parameters. Also, you should create indexes on :Post(di) and :User(id) to speed up the query.

0
votes

You can do this to delete any existing [:NEWEST_REPLY] rels:

MATCH (p:Post {id: $postId})
OPTIONAL MATCH (p)-[rel:NEWEST_REPLY]->(previousNewestReply:Reply)
WITH p,previousNewestReply,
// create a collection of size 1 or 0
     CASE WHEN NOT rel IS NULL THEN [rel] ELSE [] END AS toBeDeleted

// loop through the collection
FOREACH( tbd IN toBeDeleted | DELETE tbd )


WITH p,previousNewestReply
.....