Conditional Cypher Execution

Queries occasionally require conditional execution logic which cannot be adequately expressed in Cypher. The conditional execution procedures simulate an if / else structure, where a supplied boolean condition determines which cypher query is executed.

Procedure and Function Overview

The available procedures and functions are described below:

Qualified Name Type

apoc.when
apoc.when(condition BOOLEAN, ifQuery STRING, elseQuery STRING, params MAP<STRING, ANY>) - this procedure will run the read-only ifQuery if the conditional has evaluated to true, otherwise the elseQuery will run.

Procedure

apoc.do.when
apoc.do.when(condition BOOLEAN, ifQuery STRING, elseQuery STRING, params MAP<STRING, ANY>) - runs the given read/write ifQuery if the conditional has evaluated to true, otherwise the elseQuery will run.

Procedure

apoc.case
apoc.case(conditionals LIST<ANY>, elseQuery STRING, params MAP) - for each pair of conditional and read-only queries in the given LIST<ANY>, this procedure will run the first query for which the conditional is evaluated to true. If none of the conditionals are true, the ELSE query will run instead.

Procedure

apoc.do.case
apoc.do.case(conditionals LIST<ANY>, elseQuery STRING, params MAP<STRING, ANY>) - for each pair of conditional queries in the given LIST<ANY>, this procedure will run the first query for which the conditional is evaluated to true. If none of the conditionals are true, the ELSE query will run instead.

Procedure

WHEN Procedures

For if / else conditional logic, when procedures allow an ifQuery and elseQuery to be specified. If the conditional is true, the ifQuery will be run, and if not the elseQuery will be run.

signature

apoc.when(condition :: BOOLEAN, ifQuery :: STRING, elseQuery = :: STRING, params = {} :: MAP) :: (value :: MAP)

apoc.do.when(condition :: BOOLEAN, ifQuery :: STRING, elseQuery = :: STRING, params = {} :: MAP) :: (value :: MAP)

Read only
CALL apoc.when(
  condition: BOOLEAN,
  ifQuery: STRING,
  elseQuery: STRING,
  params: MAP)
YIELD value
Write
CALL apoc.do.when(
  condition: BOOLEAN,
  ifQuery: STRING,
  elseQuery: STRING,
  params: MAP)
YIELD value

For example, to match neighbor nodes one and two traversals away from a start node, and return a smaller set (either those one traversal away, or those that are two traversals away), run the following query:

MATCH (start:Node)-[:REL]->(a)-[:REL]->(b)
WITH collect(distinct a) as aNodes, collect(distinct b) as bNodes

CALL apoc.when(
  size(aNodes) <= size(bNodes),
  'RETURN aNodes as resultNodes',
  'RETURN bNodes as resultNodes',
  {aNodes:aNodes, bNodes:bNodes})
YIELD value

RETURN value.resultNodes as resultNodes

To conditionally set or create graph elements in cases where an account could be considered suspicious (while continuing with other query operations), use the procedure apoc.do.when.

MATCH (acc:Account)
OPTIONAL MATCH (acc)-[r:ACCESSED_BY]->(suspect:User)
WHERE suspect.id in {suspiciousUsersIdList}

CALL apoc.do.when(
  r IS NOT NULL,
  'SET acc:Suspicious',
  '',
  {acc:acc})
YIELD value

// ignore value and continue
WITH acc
...

CASE Procedures

For more complex conditional logic, case procedures allow for a variable-length list of condition / query pairs, where the query following the first conditional evaluating to true is executed. An elseQuery block is executed if none of the conditionals are true.

signature

apoc.case(conditionals :: LIST<ANY>, elseQuery = :: STRING, params = {} :: MAP) :: (value :: MAP)

apoc.do.case(conditionals :: LIST<ANY>, elseQuery = :: STRING, params = {} :: MAP) :: (value :: MAP)

Read only
CALL apoc.case(
  conditionals: List of alternating BOOLEAN/STRING,
  elseQuery: STRING,
  params: MAP)
YIELD value
Write
CALL apoc.do.case(
  conditionals: List of alternating BOOLEAN/STRING,
  elseQuery: STRING,
  params: MAP)
YIELD value

To MATCH selection nodes in a column, it is possible to use different MATCH clauses depending on the query parameters, or the data already in the graph.

MATCH (me:User {id:$myId})
CALL apoc.case([
  $selection = 'friends', "RETURN [(me)-[:FRIENDS]-(friend) | friend] as selection",
  $selection = 'coworkers', "RETURN [(me)-[:WORKS_AT*2]-(coworker) | coworker] as selection",
  $selection = 'all', "RETURN apoc.coll.union([(me)-[:FRIENDS]-(friend) | friend], [(me)-[:WORKS_AT*2]-(coworker) | coworker]) as selection"],
  'RETURN [] as selection',
  {me:me}
)
YIELD value
RETURN value.selection as selection;

To create different relationship types between two nodes based on a value, run the following statement:

MATCH (me:User {id:$myId})
MATCH (friend:User {id:$friendId})
CALL apoc.do.case([
  $selection = 'friends', "MERGE (me)-[rel:FRIENDS]->(friend) RETURN rel",
  $selection = 'coworkers', "MERGE (me)-[rel:CO_WORKER]->(friend) RETURN rel"],
  'MERGE (me)-[rel:CONNECTED]->(friend) RETURN rel',
  {me:me, friend:friend}
)
YIELD value
RETURN value.rel as rel;