Running Cypher fragments

We can use Cypher as a safe, graph-aware, partially compiled scripting language within APOC.

Procedure Overview

The supported procedures are described in the table below:

type qualified name signature description

procedure

apoc.cypher.doIt

apoc.cypher.doIt(cypher :: STRING?, params :: MAP?) :: (value :: MAP?)

apoc.cypher.doIt(fragment, params) yield value - executes writing fragment with the given parameters

procedure

apoc.cypher.run

apoc.cypher.run(cypher :: STRING?, params :: MAP?) :: (value :: MAP?)

apoc.cypher.run(fragment, params) yield value - executes reading fragment with the given parameters - currently no schema operations

procedure

apoc.cypher.runMany

apoc.cypher.runMany(cypher :: STRING?, params :: MAP?, config = {} :: MAP?) :: (row :: INTEGER?, result :: MAP?)

apoc.cypher.runMany('cypher;\nstatements;',{params},[{statistics:true,timeout:10}]) - runs each semicolon separated statement and returns summary - currently no schema operations

procedure

apoc.cypher.parallel

apoc.cypher.parallel(fragment :: STRING?, params :: MAP?, parallelizeOn :: STRING?) :: (value :: MAP?)

procedure

apoc.cypher.parallel2

apoc.cypher.parallel2(fragment :: STRING?, params :: MAP?, parallelizeOn :: STRING?) :: (value :: MAP?)

procedure

apoc.cypher.mapParallel

apoc.cypher.mapParallel(fragment :: STRING?, params :: MAP?, list :: LIST? OF ANY?) :: (value :: MAP?)

apoc.cypher.mapParallel(fragment, params, list-to-parallelize) yield value - executes fragment in parallel batches with the list segments being assigned to _

procedure

apoc.cypher.mapParallel2

apoc.cypher.mapParallel2(fragment :: STRING?, params :: MAP?, list :: LIST? OF ANY?, partitions :: INTEGER?, timeout = 10 :: INTEGER?) :: (value :: MAP?)

apoc.cypher.mapParallel2(fragment, params, list-to-parallelize) yield value - executes fragment in parallel batches with the list segments being assigned to _

function

apoc.cypher.runFirstColumn

apoc.cypher.runFirstColumn(cypher :: STRING?, params :: MAP?, expectMultipleValues = true :: BOOLEAN?) :: (ANY?)

use either apoc.cypher.runFirstColumnMany for a list return or apoc.cypher.runFirstColumnSingle for returning the first row of the first column

function

apoc.cypher.runFirstColumnMany

apoc.cypher.runFirstColumnMany(cypher :: STRING?, params :: MAP?) :: (LIST? OF ANY?)

apoc.cypher.runFirstColumnMany(statement, params) - executes statement with given parameters, returns first column only collected into a list, params are available as identifiers

function

apoc.cypher.runFirstColumnSingle

apoc.cypher.runFirstColumnSingle(cypher :: STRING?, params :: MAP?) :: (ANY?)

apoc.cypher.runFirstColumnSingle(statement, params) - executes statement with given parameters, returns first element of the first column only, params are available as identifiers

Example: Fast Node-Counts by Label

We can quickly compute the number of nodes for a specific label using the count function, but only if that’s the only single thing in the query. For example:

MATCH (:Person) RETURN count(*);

We can also combine several with UNION ALL:

Works
MATCH (:Person) RETURN count(*)
UNION ALL
MATCH (:Movie) RETURN count(*);

But we can’t do the same thing using the WITH clause:

Doesn’t work
MATCH (:Person)
WITH count(*) as people
MATCH (:Movie) RETURN people, count(*) as movies;

This query will work out the count by iterating over all nodes, which is a very slow operation

We can use apoc.cypher.run to construct the COUNT() statements and run each of them individually, so it completes in a few ms.

CALL db.labels() yield label
CALL apoc.cypher.run("match (:`"+label+"`) return count(*) as count", null) yield value
return label, value.count as count

You can use a similar approach to get the property-keys per label:

CALL db.labels() yield label
CALL apoc.cypher.run("MATCH (n:`"+label+"`) RETURN keys(n) as keys LIMIT 1",null) yield value
RETURN label, value.keys as keys