Differences in Cypher implementations
Memgraph implements the openCypher (opens in a new tab) query language and aims to be as close as possible to the most commonly used openCypher implementations. Still, there are some differences in Memgraph Cypher implementation that enhance the user experience.
Difference from Neo4j's Cypher implementation
The openCypher initiative stems from Neo4j's Cypher query language. Following is a list of the most important differences between Neo4j's and Memgraph's Cypher implementation is for users who are already familiar with Neo4j.
Indexes and constraints
In Memgraph, indexes are not created in advance and creating constraints does not imply index creation. Memgraph supports label-property and label node indexes, node property existence and uniqueness constraints.
By default, Neo4j will create a range index for the CREATE ... INDEX ...
command. Here is an example of such a query:
CREATE INDEX node_range_index_name FOR (n:Person) ON (n.surname);
Memgraph does not support the same syntax. To create such an index in Memgraph, run:
CREATE INDEX ON :Person(surname);
To create only label index in Memgraph, run the following query:
CREATE INDEX ON :Person;
Memgraph does not support composite indexes. -> Track progress on GitHub (opens in a new tab) and add a comment if you require such a feature.
You can instruct the planner to use specific index(es) in Memgraph by using the syntax below:
USING INDEX :Label1, :Label2 ...;
USING INDEX :Label(property) ...;
Besides index hinting, the ANALYZE GRAPH
feature can also be applied to optimize performance.
To create a node property existence constraint in Neo4j, you would run the following query:
CREATE CONSTRAINT author_name
FOR (author:Author) REQUIRE author.name IS NOT NULL;
To achieve the same in Memgraph, change the syntax to:
CREATE CONSTRAINT ON (author:Author) ASSERT EXISTS (author.name);
To drop a node property existence constraint in Neo4j, you would run the following query:
DROP CONSTRAINT author_name;
To achieve the same in Memgraph, change the syntax to:
DROP CONSTRAINT ON (author:Author) ASSERT EXISTS (author.name);
To create a node property uniqueness constraint in Neo4j, you would run the following query:
CREATE CONSTRAINT book_isbn
FOR (book:Book) REQUIRE book.isbn IS UNIQUE
To achieve the same in Memgraph, change the syntax to:
CREATE CONSTRAINT ON (book:Book) ASSERT book.isbn IS UNIQUE;
To drop a node property uniqueness constraint in Neo4j, you would run the following query:
DROP CONSTRAINT book_isbn;
To achieve the same in Memgraph, change the syntax to:
DROP CONSTRAINT ON (book:Book) ASSERT book.isbn IS UNIQUE;
Shortest path
In Neo4j, to find the shortest possible path between two nodes, you would use the shortestPath
algorithm:
MATCH p=shortestPath(
(:Person {name:"Keanu Reeves"})-[*]-(:Person {name:"Tom Hanks"})
)
RETURN p
Memgraph offers fast deep path traversals as built-in graph algorithms, including BFS, DFS, WSP and ASP algorithms. That is a bit different from the shortestPath
and allShortestPaths
functions you might be used to, but with such algorithms being built in, Memgraph offers fast traversals. Here is an example of how you would rewrite the above query to work in Memgraph:
MATCH p=(:Person {name:"Keanu Reeves"})-[*BFS]-(:Person {name:"Tom Hanks"})
RETURN p
NOT label expression
In Neo4j, you can use the NOT
label expression (!
):
MATCH (:Person {name:'Tom Hanks'})-[r:!ACTED_IN]->(m:Movie)
Return type(r) AS type, m.title AS movies
In Memgraph, such a construct is not supported, but there is still a workaround:
MATCH (p:Person {name:'Tom Hanks'})-[r]->(m:Movie)
WHERE type(r) != "ACTED_IN"
RETURN type(r) AS type, m.title AS movies;
Search for patterns of a fixed length
In Neo4j, to search for patterns of a fixed length, you would use the following construct:
MATCH (tom:Person {name:'Tom Hanks'})--{2}(colleagues:Person)
RETURN DISTINCT colleagues.name AS name, colleagues.born AS bornIn
ORDER BY bornIn
LIMIT 5
Memgraph does not support such a construct, but since it has built-in traversals, you can achieve the same with the depth-first search (DFS) algorithm:
MATCH (tom:Person {name:'Tom Hanks'})-[*2]-(colleagues:Person)
RETURN DISTINCT colleagues.name AS name, colleagues.born AS bornIn
ORDER BY bornIn
LIMIT 5
Similarly, to match a graph for patterns of a variable length, you would run the following query in Neo4j:
MATCH (p:Person {name:'Tom Hanks'})--{1,4}(colleagues:Person)
RETURN DISTINCT colleagues.name AS name, colleagues.born AS bornIn
ORDER BY bornIn, name
LIMIT 5
In Memgraph, again use DFS:
MATCH (p:Person {name:'Tom Hanks'})-[*1..4]-(colleagues:Person)
RETURN DISTINCT colleagues.name AS name, colleagues.born AS bornIn
ORDER BY bornIn, name
LIMIT 5
Unsupported constructs
CALL subqueries in transactions
Such a query is not supported in Memgraph, but you can use the periodic module to execute a query periodically in batches.
EXISTS subqueries
Such clause is not supported in Memgraph, but you can use exists()
pattern function with the WHERE
clause to filter with pattern expressions.
The following constructs are not yet supported in Memgraph:
EXISTS
subquery withWHERE
clause -> Track progress on GitHub (opens in a new tab) and add a comment if you require such a feature.- Nesting
EXISTS
subqueries -> Track progress on GitHub (opens in a new tab) and add a comment if you require such a feature. EXISTS
subquery outside of aWHERE
clause -> Track progress on GitHub (opens in a new tab) and add a comment if you require such a feature.
For all other unsupported constructs that you require, please open an issue on our GitHub repository (opens in a new tab). Learn more in our Community Call on Subqueries & Patterns in Filtering Clauses (opens in a new tab).
COUNT subqueries
Such a construct is not supported in Memgraph, but you can use count()
aggregation function to count the number of non-null values returned by the expression.
COLLECT subqueries
Such a construct is not supported in Memgraph, but you can use collect()
aggregation function to return a single aggregated list from provided values.
Patterns in expressions
Patterns in expressions are supported in Memgraph in particular functions, like exists(pattern)
.
In other cases, Memgraph does not yet support patterns in functions, e.g. size((n)-->())
.
Most of the time, the same functionalities can be expressed differently in Memgraph
using OPTIONAL
expansions, function calls, etc.
List comprehension
The following type of query is not yet supported in Memgraph:
MATCH (keanu:Person {name:'Keanu Reeves'})
RETURN [x IN keanu.resume WHERE x contains 'The Matrix'] AS matrixList
Unsupported expressions
Cypher expressions
- Numerical:
- An octal
INTEGER
literal (starting with0o
):0o1372
,0o5671
- A
FLOAT
literal:Inf
,Infinity
,NaN
- An octal
- Boolean:
- Label and relationship type expressions:
(n:A|B)
,()-[r:R1|R2]->()
-> Track progress on GitHub (opens in a new tab) and add a comment if you require such a feature.
- Label and relationship type expressions:
Conditional expressions (CASE
)
- More than one value after
WHEN
operator:Here is a workaround in Memgraph:MATCH (n:Person) RETURN CASE n.eyes WHEN 'blue' THEN 1 WHEN 'brown', 'hazel' THEN 2 ELSE 3 END AS result, n.eyes
-> Track progress on GitHub (opens in a new tab) and add a comment if you require such a feature.MATCH (n:Person) RETURN CASE WHEN n.eyes='blue' THEN 1 WHEN n.eyes='brown' OR n.eyes='hazel' THEN 2 ELSE 3 END AS result, n.eyes;
Type predicate expressions
The following expression is not supported in Memgraph:
UNWIND [42, true, 'abc'] AS val
RETURN val, val IS :: INTEGER AS isInteger
Still, you can check the value type with the valueType()
scalar function, which returns the value type of the object in textual format:
UNWIND [42, true, 'abc'] AS val
RETURN val, valueType(val) = "INTEGER"
Unsupported functions
Functions for converting data values:
toBooleanList()
toBooleanOrNull()
toFloatList()
toFloatOrNull()
toIntegerList()
toIntegerOrNull()
toStringList()
toStringOrNull()
Predicate functions:
exists(n.property)
- can be expressed usingn.property IS NOT NULL
isEmpty()
Scalar functions:
elementId()
-id()
can be used insteadlength()
-size()
can be used insteadnullIf()
Aggregating functions:
percentileCont()
,percentileDisc()
stDev()
,stDevP()
Mathematical functions:
isNan()
cot()
degrees()
haversin()
radians()
String functions:
normalize()
Datetime functions:
time()
Memgraph's Cypher extension
Besides implementing openCypher, Memgraph created various language extensions to provide an enhanced user experience. Here are some of the improvements:
For all other unsupported constructs that you require, please open an issue on our GitHub repository (opens in a new tab).