A new universe for your graph data.Meet Galactus DB
GALACTUS DB WIKIDeployment · Queries · Operations

Operators and expressions

Wiki / Cypher query language

On this page

Literals

RETURN 42, -7, 3.14, true, false, null, 'single', "double";
RETURN [1, 2, 3], ['a', true, 3], [];                 // list literals
RETURN {name: 'Ada', age: 36, tags: ['x', 'y']};      // map literal

Property and variable access:

MATCH (p:Person) RETURN p.name, p.address.city;       // dotted property access

Arithmetic operators

OperatorMeaningNotes
+addition / string concatenation / list concat'a' + 'b' → 'ab'
-subtraction; unary negation-x
*multiplication
/divisioninteger/integer is integer division; division by zero is an error
%modulo / remaindermodulo by zero is an error
RETURN 2 + 3 * 4 AS r;            // 14 (precedence respected)
RETURN (2 + 3) * 4 AS r;         // 20
RETURN 'Hello, ' + 'world';      // 'Hello, world'
MATCH (p:Person) RETURN p.age * 12 AS months, -p.age AS neg;

Integer arithmetic is overflow-checked — an overflowing operation is a clean error, not a wraparound.

Comparison operators

OperatorMeaning
=equal
<>not equal
<, >, <=, >=ordering comparisons

Semantics (Cypher value comparison):

  • 1 = 1.0 is true (numeric equality across int/float).
  • Any comparison with null yields null (not true/false).
  • NaN is never equal to anything, including itself (NaN = NaN → false) — and NaN cannot be stored as a property anyway.
  • Ordering (<, >, <=, >=) between incomparable cross-type operands yields null (e.g. a string vs a number). Numbers compare numerically.
RETURN 1 = 1.0;        // true
RETURN 1 < null;       // null
RETURN 'a' < 'b';      // true

Boolean operators & three-valued logic

AND, OR, NOT operate on three values: true, false, null (Kleene logic). XOR exists too — see Operators and expressions.

aba AND ba OR b
truetruetruetrue
truefalsefalsetrue
truenullnulltrue
falsenullfalsenull
nullnullnullnull

NOT null is null. A WHERE keeps only rows whose predicate is true (both false and null are filtered out).

MATCH (p:Person)
WHERE p.active = true AND NOT p.archived = true
RETURN p.name;

Both operands are evaluated eagerly — there is no short-circuit. false AND f(x) still evaluates f(x), so a function that can error (say, apoc.convert.fromJsonMap on a malformed blob) aborts the query even when the other operand already decides the result. CASE branches are lazy (Operators and expressions); use one as the guard:

// Guard absent data and text that does not start with an object prefix:
WITH {data: '{"channel":"web"}'} AS m
WHERE any(d IN [CASE WHEN m.data STARTS WITH '{'
                THEN apoc.convert.fromJsonMap(m.data) ELSE NULL END]
          WHERE d.channel = 'web')
RETURN m.data;

A leading { does not validate JSON. Malformed object text still raises a parse error; use this guard only when object-prefixed values are valid JSON.

NULL predicates

MATCH (p:Person) WHERE p.nick IS NULL     RETURN p.name;
MATCH (p:Person) WHERE p.nick IS NOT NULL RETURN p.name;

IN (list membership)

MATCH (p:Person) WHERE p.name IN ['Ada', 'Bob'] RETURN p;
RETURN 3 IN [1, 2, 3] AS yes;     // true

IN uses the same value-equality as =, including its null behaviour.

String predicates

PredicateMeaning
STARTS WITHprefix test
ENDS WITHsuffix test
CONTAINSsubstring test
MATCH (p:Person)
WHERE toLower(p.name) STARTS WITH 'a'
   OR p.email ENDS WITH '@example.com'
   OR p.bio CONTAINS 'graph'
RETURN p.name;

There is no regex operator: =~ is a parse error (unexpected character '~') — The engine has no third-party dependencies and ships no regex engine. Case-insensitive matching is toLower(x) CONTAINS $term; for "does this JSON property match" parse the blob with apoc.convert.fromJsonMap and compare the value (guarded against non-JSON data — see Operators and expressions).

List & map operations

Indexing (e[i]) and slicing (e[lo..hi]) of lists:

RETURN [10, 20, 30][0] AS first;      // 10
RETURN [10, 20, 30][-1] AS last;      // 30 (negative index from the end)
RETURN [10, 20, 30, 40][1..3] AS mid; // [20, 30] (half-open: lo inclusive, hi exclusive)
RETURN substring('graph', 0, 3) AS pre; // 'gra'; string slicing is unsupported

Map field access uses dotted or bracket notation:

RETURN {a: 1, b: 2}.a AS x;           // 1
WITH {a: 1, b: 2} AS m RETURN m.b;    // 2

Building structures from data:

MATCH (p:Person)
RETURN [p.name, p.age] AS pair, {id: p.email, name: p.name} AS rec;

Pattern existence (EXISTS { … })

A pattern can be used as a boolean predicate:

MATCH (p:Person)
WHERE EXISTS { (p)-[:KNOWS]->(:Person {name: 'Ada'}) }
RETURN p.name;

Function calls in expressions

Scalar and namespaced functions are ordinary expressions (see Scalar functions):

RETURN toUpper('ada'), size([1, 2, 3]), coalesce(null, null, 'fallback');
RETURN point({x: 0, y: 0}).x AS px;            // call then field access
RETURN gds.similarity.cosine([1, 0], [1, 1]);  // namespaced (dotted) function

XOR

Exclusive-or, between OR (looser) and AND (tighter) in precedence. Three-valued: NULL if either side is NULL, else true when exactly one side is true.

RETURN true XOR false;     // true
RETURN true XOR true;      // false
RETURN null XOR true;      // null

CASE

Both forms are supported. The generic form tests boolean predicates; the simple form compares an operand for equality. The first match wins; with no match the result is the ELSE value, or NULL.

// generic
MATCH (p:Person)
RETURN CASE WHEN p.age >= 18 THEN 'adult' ELSE 'minor' END AS bracket;

// simple
RETURN CASE size(['a','b']) WHEN 0 THEN 'empty' WHEN 2 THEN 'pair' ELSE 'other' END;

List & pattern comprehensions

A list comprehension iterates a list, optionally filtering and mapping:

RETURN [x IN [1,2,3,4] WHERE x % 2 = 0 | x * 10] AS evens;   // [20, 40]
RETURN [x IN range(1,3) | x * x] AS squares;                 // [1, 4, 9]

A pattern comprehension matches a pattern in the current row's context and projects an expression per match:

MATCH (a:Person {name: 'Ada'})
RETURN [(a)-[:KNOWS]->(f) | f.name] AS friends;

reduce

Fold a list, threading an accumulator:

RETURN reduce(total = 0, x IN [1,2,3,4] | total + x) AS sum;        // 10
RETURN reduce(s = '', x IN ['a','b','c'] | s + x) AS joined;        // 'abc'

Map projection

Build a map from a node/relationship/map and a list of selectors: .prop copies a property, .* copies all of them, key: expr adds a computed entry, and a bare variable copies that variable.

MATCH (p:Person)
RETURN p {.name, .age, older: p.age + 1} AS view;
MATCH (p:Person) RETURN p {.*} AS all_props;

Inline pattern predicates

A WHERE may appear inside a node pattern; it is evaluated after the pattern is bound and can reference its variables:

MATCH (p:Person WHERE p.age > 18) RETURN p.name;
MATCH (a:Person)-[:KNOWS]->(b:Person WHERE b.age > a.age) RETURN b.name;

Operator precedence (high → low)

  1. Property access ., indexing/slicing [...], function call f(...), map projection { ... }
  2. Unary -, NOT
  3. *, /, %
  4. +, -
  5. Comparisons = <> < > <= >=, IN, STARTS WITH/ENDS WITH/CONTAINS, IS NULL/IS NOT NULL
  6. AND
  7. XOR
  8. OR

Use parentheses to be explicit when in doubt: (a OR b) AND c. CASE and the comprehension/reduce forms are primary expressions (they bind tightest).

List predicates and count subqueries

any, all, none and single bind a list element and evaluate a predicate. Empty lists return false, true, true and false respectively. A null list yields null. COUNT { pattern } counts matches without materialising an intermediate result list; EXISTS { pattern } can stop at the first match.

RETURN any(x IN [1,2,3] WHERE x > 2), all(x IN [1,2,3] WHERE x > 0);
MATCH (p:Person) RETURN p.name, COUNT { (p)-[:KNOWS]->() } AS friends;

Indexes and constraints · Procedure directory · Transactions and concurrency

Planning a deployment? Review compatibility and licence setup for your instance.