'WITH' and nested apoc statements

My use case is

  • match a node
  • iterate over a list (passed in a parameter) that contains information to match related nodes. This includes things like relationship names, which AFAIK need to apoc in order to be parameterised

This is how far I've got successfully

call apoc.cypher.mapParallel('call apoc.cypher.run("MATCH (p:" + _.type + ")<-[:"+_.relName+"]-(t {code:$code}) RETURN p, t", _) yield value RETURN value', {}, $bits) yield value
RETURN value

I'm using run inside mapParallel in order to cover using some properties of each list item (which are objects) as parameters to match on, while using others as part of a concatenated cypher fragment (maybe there is a better way... but it works so far)

I'm now at the point where I want to match a node first, and then pass this in, so something like the below:

MATCH (t:Team {code: "reliability-engineering"})
WITH t
call apoc.cypher.mapParallel('call apoc.cypher.run("MATCH (p:" + _.type + ")<-[:"+_.relName+"]-(t) RETURN p, t", {}) yield value RETURN value', {}, $bits) yield value
RETURN value

The above doesn't work, but I've tried various other approaches to passing t all the way to the internal MATCH query, but get either t is undefined errors or Parameter maps cannot be used in MATCH patterns (use a literal map instead, eg. "{id: {param}.id}").

What is the correct way to pas references to nodes in to apoc procedures (particularly nested ones)?

Try this:

call apoc.cypher.mapParallel('call apoc.cypher.run(
"MATCH (p:" + _.type + ")<-[:"+_.relName+"]-(t:Team {code: "reliability-engineering"}) RETURN p, t", {}) 
yield value RETURN value', {}, $bits) yield value
RETURN value

I recommend to use mapParallel2

which takes a list of nodes (in your case collect(t) ) to operate on.

here is an example:

MATCH (p:Page) 
WHERE p.title starts with 'T'
WITH collect(p) as pages
CALL apoc.cypher.mapParallel2("MATCH (_)-[:Link]->(p1)<-[:Link]-(p2)
WITH p2, count(*) as c where c > $count
RETURn  p2.title as title, c", {count:0}, pages, 1000) yield value
return  value.title, value.c limit 10
1 Like

But where in that is there room to pass in e.g. a list of relationship types to match in as query params? In my case Link cannot be hardcoded - they are specified in something like a $relationshipNames param, which is a list. This is why I'm using apoc in the first place, so that I can have a single query fragment that can be run multiple times with different relationship names, rather than concatenating lots of fragments together, one per relationship name

Actually, I will explain the use case in a bit more detail. It's a patch action where the payload sent lists all the relationships that should exist after the action i.e. replace all relationships. For efficiency, we do a read, diff then write, so that the query explicitly deletes some relationships, and creates others, but leaves others untouched.

Ignoring the relationship creation, the input looks a bit like:

{
   type: "System",
   code: "my-system",
   relsToDelete: [{
    relName: "MY_REL1", 
    direction: "out",
    codes: ["code1", "code2"]
  },{
    relName: "MY_REL2", 
    direction: "in",
    codes: ["code1", "code2"]
  }]
}

So the action is to query by $code and $type to find the root node, then iterate through $relsToDelete to carry out DELETE actions on relationships.