Nesting apoc.path.subgraphAll inside apoc.when

Our graph is a tree. I'm trying to build a query that given a node returns that node and optionally its ancestors and optionally its descendants. In other words I want to parameterize the query with parameters includeAncestors and includeDescendants.

This is my working query without parameters. i.e. It always returns both ancestors and descendants (and referenced nodes).

		MATCH (n:Entity {asset_id: $assetId, version: $version, id: $entityId})
		with n
		CALL apoc.path.subgraphAll(n, {
			WHERE $ancestors=True
			relationshipFilter : 'CHILD_OF>|<ATTACHED_TO',
			optional: true
		}) yield nodes, relationships
		with n, nodes as ascNodes, relationships as ascRel
		CALL apoc.path.subgraphAll(n, {
			WHERE $descendants=True
			relationshipFilter : '<CHILD_OF|<ATTACHED_TO',
			optional: true
		}) yield nodes, relationships
		with n, nodes as descNodes, relationships as descRel , ascNodes, ascRel
		CALL apoc.path.subgraphAll(n, {
			relationshipFilter : '<CHILD_OF|<ATTACHED_TO|REFERS_TO',
			optional: true
		}) yield nodes, relationships
		with n, nodes as refNodes, relationships as refRel , ascNodes, ascRel, descNodes, descRel
		CALL apoc.path.subgraphAll(refNodes, {
			relationshipFilter : 'CHILD_OF>|<ATTACHED_TO',
			optional: true
		}) yield nodes, relationships
		with n, nodes as refAscNodes, relationships as refAscRel, refNodes, refRel, ascNodes, ascRel, descNodes, descRel
		RETURN DISTINCT *

Here's my first attempt to parameterize by an includeAncestors parameter. I modified the query as follows.

MATCH (n:Entity {asset_id: $assetId, version: $version, id: $entityId})
with n
CALL apoc.when(
    $includeAncestors,
    "CALL apoc.path.subgraphAll(n, {
        relationshipFilter : 'CHILD_OF>|<ATTACHED_TO',
        optional: true
    }) yield nodes, relationships",
    '',
    {n:n}
) yield nodes, relationships
CALL apoc.path.subgraphAll(n, {
    WHERE $ancestors=True
    relationshipFilter : 'CHILD_OF>|<ATTACHED_TO',
    optional: true
}) yield nodes, relationships
with n, nodes as ascNodes, relationships as ascRel
CALL apoc.path.subgraphAll(n, {
    WHERE $descendants=True
    relationshipFilter : '<CHILD_OF|<ATTACHED_TO',
    optional: true
}) yield nodes, relationships
with n, nodes as descNodes, relationships as descRel , ascNodes, ascRel
CALL apoc.path.subgraphAll(n, {
    relationshipFilter : '<CHILD_OF|<ATTACHED_TO|REFERS_TO',
    optional: true
}) yield nodes, relationships
with n, nodes as refNodes, relationships as refRel , ascNodes, ascRel, descNodes, descRel
CALL apoc.path.subgraphAll(refNodes, {
    relationshipFilter : 'CHILD_OF>|<ATTACHED_TO',
    optional: true
}) yield nodes, relationships
with n, nodes as refAscNodes, relationships as refAscRel, refNodes, refRel, ascNodes, ascRel, descNodes, descRel
RETURN DISTINCT *

But I get the following syntax error.
`

Unknown procedure output: `nodes` (line 11, column 11 (offset: 322))
" ) yield nodes, relationships"
^

Obviously I don't quite have it set up correctly. Can someone suggest a fix to my query?

Thanks,

Michael-

Here's the syntax I got to work regarding nested apoc calls.

CALL apoc.when(
    false,
    "CALL apoc.path.subgraphAll(n, {
        relationshipFilter : 'CHILD_OF>|<ATTACHED_TO',
        optional: true
    }) YIELD nodes, relationships
    RETURN nodes, relationships",
    "WITH n as nodes, [] as relationships
    RETURN nodes, relationships",
    {n:n}
) YIELD value
RETURN value

Duh, even simpler. I can do this without a nested apoc, by using the maxLevel parameter to the subgraphAll procedure as shown below.

MATCH (n:Entity {asset_id: "urn:aaid:sc:VA6:bbb6472c-34d5-4cf0-92e4-e2569c13b159", version: "#head", path: "artwork"})
with n
CALL apoc.path.subgraphAll(n, {
    relationshipFilter : 'CHILD_OF>|<ATTACHED_TO',
    optional: true,
    maxLevel: -1
}) YIELD nodes, relationships
RETURN nodes, relationships

If I want to include ancestors, in this case, the set maxLevel to -1. If I don't want to include ancestors, then set maxLevel to 0.

Did you ever get an answer to this?

I am seeking something similar, my query is relatively simple

MATCH (p)<-[:partOf0..]-(a:NodeType {uuid:'ae66e077-f7ea-410d-9112-5160c396dfa0'})<-[:partOf0..]-(d: NodeType) RETURN p, d

With this query, I get lots of duplicates when I fetch the JSON - so won't be efficient if I have thousands of nodes.

I am only interested in returning something like:

uuid, a few properties, [ descendants uuid list ]

but not sure how to coalesce p & d in order to use collections

This does not seem similar to the original post.

You can use 'distinct' to eliminate duplicate rows in your results.

MATCH (p)<-[:partOf0..]-(a:NodeType {uuid:'ae66e077-f7ea-410d-9112-5160c396dfa0'})<-[:partOf0..]-(d: NodeType) 
RETURN distinct p, d

You state you want to return something like 'uuid, a few properties, [ descendants uuid list ]'. What are the descendent nodes you want to return? Your query returns the start and end node of your pattern. Are you trying to get all the nodes in the path for each instance of 'p'?

If you can provide a little more clarity, maybe we can help.

Thanks for answering - the original post asked "I'm trying to build a query that given a node returns that node and optionally its ancestors and optionally its descendants." - which is similar to what I am aiming at (he went on a different direction).

To answer your questions: I have a directed node at any point in a graph, but I only want predecessors 'up to a parent' (same type of node, but has an additional label) - which is just a list (P-...->refNode). But I want all of its descendants (which can be a graph).

I think I figured it out during my dog walk:

I have done a union of "give me ancestors" and "give me descendants" (node, [list of descendants]).

I don't get why it is so complicated :slight_smile:

MATCH (a:NodeType {uuid:'ae66e077-f7ea-410d-9112-5160c396dfa0'})<-[r:partOf*0..]-(p:NodeType) RETURN elementId(p), collect(r) AS endNodes

It returns the elementId per node (good) but the payload for the relationships is:

[[
{
  "identity": 134,
  "start": 6468,
  "end": 6335,
  "type": "partOf",
  "properties": {

  },
  "elementId": "5:d2fb2e08-d9a8-4ace-b7b6-305175ee9551:134",
  "startNodeElementId": "4:d2fb2e08-d9a8-4ace-b7b6-305175ee9551:6468",
  "endNodeElementId": "4:d2fb2e08-d9a8-4ace-b7b6-305175ee9551:6335"
}

And I can't figure out how to return just the endNodeElementId ? (I don't need the rest, and it would save bandwidth and processing time). Especially if you can have hundreds of thousands of nodes ...