neo4jcypher

Behavior of the ALL() Predicate Function in Neo4j


I have a question regarding the behavior of the ALL() predicate function in Neo4j 5.26.2. I have no issues with (1) and (2), however, I'm finding it unusual that I get 3 hits each with (3) and (4). Is this the correct behavior (as per specification)?

(1)

MATCH(p:Parent)
WHERE ALL(x IN p.array WHERE x = 2)
RETURN p.id, p.array
;
p.id    p.array
2   [2, 2, 2]

(2)

MATCH(p:Parent)--(c)
WITH p, COLLECT(c.parent) AS parents
WHERE ALL(x IN parents WHERE x = 2)
RETURN p.id, parents
;
p.id    parents
2   [2, 2, 2]

(3)

MATCH(p:Parent)
WHERE ALL(x IN p.empty_array WHERE x = 2)
RETURN p.id, p.empty_array
;
p.id    p.empty_array
1   []
2   []
3   []

(4)

MATCH(p:Parent)--(c)
WITH p, COLLECT(c.does_not_exist) AS does_not_exists
WHERE ALL(x IN does_not_exists WHERE x = 2)
RETURN p.id, does_not_exists
;
p.id    does_not_exists
1   []
2   []
3   []

You can create test data with the following Cypher statement:

WITH
    RANGE(1,3) AS parents,
    RANGE(1,3) AS children
FOREACH (parent IN parents | 
    MERGE (p:Parent{id:parent, array:[], empty_array:[]})
    FOREACH (child IN children | 
        CREATE (c:Child{id:parent*10 + child, parent:parent})
        MERGE (p)-[:CHILD]->(c)
        SET p.array = p.array + parent
    )
);

Displaying test data:

MATCH(p:Parent)--(c:Child)
RETURN *;

Deleting test data:

MATCH(p:Parent)--(c:Child)
DETACH DELETE p, c;

Solution

  • The all() predicate function returns true for empty lists because it is vacuously true. It's consistent with the other predicate functions.

    For example, the contradiction of all(x IN [] WHERE P(x)) is any(x IN [] WHERE P(x)). In the latter case, there does not exist an x for which P(x), and so it is always false.

    For none(x IN [] WHERE Q(x)), we can see it is equivalent to all(x IN [] WHERE NOT Q(x)), and so it is also (vacuously) true.

    See this example query:

    RETURN all(x IN [] WHERE x > 0),     // TRUE
           none(x IN [] WHERE x > 0),    // TRUE
           any(x IN [] WHERE NOT x > 0)  // FALSE