Updating node locks outgoing relation deletion for APOC but not for normal queries

So I am right now noticing a behaviour that I can not make sense of from the documentation.

Let's say I have a node D1 of type Dataset and I have 3 other nodes C1, C2, C3 of type CompanyDepartment attached to it.

Now I want to do two things

  1. Update node D1
  2. Detach Delete C1, C2, C3

A simple query that works is:

MATCH (d: Dataset { id: "D1" })
SET d.updatedAt = datetime()
WITH d
OPTIONAL MATCH (d)-[r:ENTITY]->(draft_entities)
DETACH DELETE draft_entities

But I am dealing with a lot of entities, so I want to put batching into it so I decided to use an APOC function

MATCH (d: Dataset { id: "D1" })
SET d.updatedAt = datetime()
WITH d
CALL apoc.periodic.iterate(
    '   WITH $d as d
        OPTIONAL MATCH (d)-[r:ENTITY]->(draft_entities)
        RETURN draft_entities
    ',
    '  
        DETACH DELETE draft_entities // Or we can also just do DELETE r for testing 
    ',
    { batchSize: 100, parallel: false, params: { d: d } }
) YIELD batches AS draft_batches, total AS draft_total
RETURN draft_total

But when I run the query like this it gets stuck, it keeps running forever. From a lot of debugging it seems to me that when we SET something on node, it blocks it blockes the deletion for it's outgoing relations as well. We can update them but not delete them.

Is my assumption correct? If yes can you point me to the documentation of that explains this difference in behaviour for APOC? Intutively, updating a node should not lock the outgoing relations in any way. EXPLAIN isn't showing anything meaningful as it's an APOC procedure call.

I am using Neo4j 5.23. This can be reproduced using Neo4j browser UI, but we also get the same behaviour using javascript driver.

Ideally I want to do the SET and DELETE in two different queries in the same transaction but the issue is the same.

The data can be created for testing these queries using:

CREATE (d:Dataset {id: "D1", name: "Dataset A"})
CREATE (cd1:CompanyDepartment {id: "CD1", name: "Department 1"})
CREATE (cd2:CompanyDepartment {id: "CD2", name: "Department 2"})
CREATE (cd3:CompanyDepartment {id: "CD3", name: "Department 3"})
CREATE (d)-[:ENTITY]->(cd1)
CREATE (d)-[:ENTITY]->(cd2)
CREATE (d)-[:ENTITY]->(cd3)
RETURN d, cd1, cd2, cd3

The apoc procedure will create its own transactions. I guess the node is locked from the first transaction and you are not allow to edit it, including adding/removing relationships. I think this makes sense, but I don’t have knowledge of what the system is doing.

You can move the set to after the apoc procedure so the node is not locked within the apoc procedure. It is the set that locks it. See if that helps.

Heu @glilienfield,
Thanks for replying. Even if I make the dataset node change update using apoc.cypher.doIt, the issue still persists. And why do you think this behaviour makes sense? Why should a node's update lock deletion of it's outgoing edges?
The default non-apoc behaviour of Neo4j makes more sense to me. I can not find something like that in documentation where it says updation of node locks outgoing edges from deletion.

Here are the docs on locking: Concurrent data access - Operations Manual

Does the following work;

MATCH (d: Dataset { id: "D1" })
CALL apoc.periodic.iterate(
    '   WITH $d as d
        OPTIONAL MATCH (d)-[r:ENTITY]->(draft_entities)
        RETURN draft_entities
    ',
    '  
        DETACH DELETE draft_entities // Or we can also just do DELETE r for testing 
    ',
    { batchSize: 100, parallel: false, params: { d: d } }
) YIELD batches AS draft_batches, total AS draft_total
SET d.updatedAt = datetime()
RETURN draft_total

Yes of course, it works and that's the work around I used for my realy case right now. But it's not intuative so I wanted to understand better the mechanism behind it.

It says updating a node property does a node lock (NOT a relationship lock), does my case come under additional lock in the highlighted text?