Dr. Strangelove
Dr. Strangelove

Reputation: 3328

Neo4j relationship: update a property based on its old value

When creating two relationships with the exact same properties, I want Neo4j to update a property of the relationship based on the previous value of that property. For instance, increment a counter.

Any thoughts on how I can update the following query to achieve this?

CREATE (p:Person {name: "Tom Hanks"})
CREATE (m:Movie {title:"You've Got Mail"});
MATCH (p:Person {name: "Tom Hanks"})
MATCH (m:Movie {title:"You've Got Mail"})
CALL apoc.merge.relationship(p, "ACTED_IN",
  {roles:['Joe Fox']},
  {created: datetime(),  counter: 0},
  m,
  {lastSeen: datetime(), counter: 1}  // Update this to something like `counter++`
)
YIELD rel
RETURN rel;

Upvotes: 0

Views: 385

Answers (2)

Charchit Kapoor
Charchit Kapoor

Reputation: 9284

You should first fetch the relationship using OPTIONAL MATCH and then use the counter value from that relationship. Like this:

MATCH (p:Person {name: "Tom Hanks"})
MATCH (m:Movie {title:"You've Got Mail"})
OPTIONAL MATCH (p)-[r:ACTED_IN{roles: ['Joe Fox']}]->(m)
CALL apoc.merge.relationship(p, "ACTED_IN",
  {roles:['Joe Fox']},
  {created: datetime(),  counter: 0},
  m,
  {lastSeen: datetime(), counter: r.counter + 1}
)
YIELD rel
RETURN rel;

Upvotes: 1

Davide Calarco
Davide Calarco

Reputation: 522

Declarative syntax

Here is the solution using the declarative form of Cypher:

MATCH (p:Person {name: "Tom Hanks"})
MATCH (m:Movie {title:"You've Got Mail"})
MERGE (p)-[rel:ACTED_IN {roles:['Joe Fox']}]->(m)
ON CREATE SET rel.created = datetime(), rel.counter=0
ON MATCH SET rel.lastSeen = datetime(), rel.counter=rel.counter+1
RETURN rel;

When the relationship is created, the counter is set to 0; otherwise it is updated.

Note: I took the declarative counterpart of the query from Neo4j Docs, and I added the part you're interested to.

Procedural syntax

If you are constrained or prefer using a procedural approach:

MATCH (p:Person {name: "Tom Hanks"})
MATCH (m:Movie {title:"You've Got Mail"})
CALL apoc.merge.relationship(p, "ACTED_IN",
  {roles:['Joe Fox']},
  {created: datetime(),  counter: -1},
  m,
  {lastSeen: datetime()}  // Update this to something like `counter++`
)
YIELD rel
SET rel.counter = rel.counter + 1
RETURN rel;

As you see, I set the initial counter to -1, so that at the end of the query it becomes 0; it is just an implementation detail, useful to avoid declaring a conditional statement between YIELD and RETURN.

Note: the YIELD instruction binds the created relationship with a name, in this case rel, in order to let you perform other modifications before the end of the query. See Neo4j Docs at the second paragraph.

Upvotes: 1

Related Questions