tshaw
tshaw

Reputation: 31

Neo4j Cypher - Conditional writes on matches

I have a database with users (u:User {id: 1}), user statuses (us:UserStatus {status: 'pending'}), and the relationships between them (u)-[hs:HAS_STATUS {from: 1541030400, to: 4102444800}]->(us).

Where user statuses can be "pending", "active" or "suspended". And 2100-01-01 is some date in the future meaning the user still has this status.

I'm trying to run a query that updates the status of the user by creating a new relationship with the new status and archives the old relationship by setting the to property to the current date.

This is what I've tried:

MERGE (u:User { id: 1 })
WITH u
MATCH (u)-[hs1:HAS_STATUS]->(us1:UserStatus)
WHERE us1.status <> 'active' AND hs1.to > 1544400000
SET hs1.to = 1544400000
MERGE (us2:UserStatus {status: 'active'})
MERGE (u)-[hs2:HAS_STATUS {from: 1544400000, to: 4102444800}]->(us2)

If the user already has a status that satisfies the WHERE clause then it is archived and the new status relationship is created. However if the user doesn't already have a status the SET clause is skipped (as intended) however the two MERGE lines are skipped also. How can I ensure that they are executed regardless of the merge?

Edit: Original query had some typos.

Upvotes: 0

Views: 226

Answers (2)

cybersam
cybersam

Reputation: 67009

[This answers your updated question]

A MATCH (without the OPTIONAL qualifier) will abort the rest of the query if the match fails.

This query shows one way to match a pattern and optionally perform a write operation if the match succeeds, without aborting the rest of the query if the match fails:

MERGE (u:User { id: 1 })
FOREACH(hs IN
  [(u)-[hs1:HAS_STATUS]->(us1:UserStatus)
        WHERE us1.status <> 'active' AND hs1.to > 1544400000 | hs1] |
  SET hs.to = 1544400000)
MERGE (us2:UserStatus {status: 'active'})
MERGE (u)-[hs2:HAS_STATUS {from: 1544400000, to: 4102444800}]->(us2);

This query uses a FOREACH clause to iterate through a list (of size 0 or 1, in this case) of matching hs1 values, setting the to value of each one to 1544400000. The list is generated by a pattern comprehension. Even if the list is empty, the rest of the query still executes.

Upvotes: 1

InverseFalcon
InverseFalcon

Reputation: 30407

EDIT: Previous answer segment removed as you said the "dates" you're using in your query are actually a stand-in for epoch seconds.

If no rows are changed, then one of two things is happening.

  1. Your MATCH (with associated WHERE) failed to find any matching pattern. You should try to just run that MATCH and WHERE to see if it returns any rows.

  2. The relationship you're trying to MERGE in already exists. You might want to try to match to that relationship (with those properties) between those two nodes and see if it already exists.

Upvotes: 0

Related Questions