# Differences in Cypher implementations

Memgraph implements the [openCypher](https://www.opencypher.org/) 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.

Memgraph accepts both its native `ON :Label(property)` / `ASSERT` syntax **and** the Neo4j-compatible `FOR (...) ON (...)` / `FOR (...) REQUIRE ...` syntax, so existing Neo4j code that creates indexes or constraints can run unchanged.

#### Indexes

The following Neo4j-style queries all work in Memgraph:

```cypher
CREATE INDEX FOR (n:Person) ON (n.surname);
CREATE INDEX person_surname FOR (n:Person) ON (n.surname);
CREATE INDEX FOR (n:Person) ON (n.age, n.country);
CREATE INDEX FOR ()-[r:KNOWS]-() ON (r.since);
```

The optional `RANGE` keyword is also accepted in the `FOR ... ON` syntax, for both nodes and relationships:

```cypher
CREATE RANGE INDEX FOR (n:Person) ON (n.surname);
CREATE RANGE INDEX FOR ()-[r:KNOWS]-() ON (r.since);
```

Neo4j's `RANGE` index is its general-purpose ordered property index, used for equality, range and prefix lookups — the same role Memgraph's label-property and edge-type property indexes already fill. `RANGE` is therefore accepted as a synonym: it maps onto the existing index with no new index type and no change in behavior.

The native Memgraph syntax remains supported as well:

```cypher
CREATE INDEX ON :Person(surname);
CREATE INDEX ON :Person;
CREATE EDGE INDEX ON :KNOWS(since);
```

You can instruct the planner to use specific index(es) in Memgraph by using the syntax below:
```cypher
USING INDEX :Label1, :Label2 ...;
USING INDEX :Label(property) ...;
```

Besides index hinting, the [`ANALYZE GRAPH`](https://memgraph.com/docs/fundamentals/indexes#analyze-graph) feature can also be applied to [optimize performance](https://memgraph.com/docs/querying/best-practices).

- [Read more about indexes](https://memgraph.com/docs/fundamentals/indexes)

#### Constraints

Existence, uniqueness, and type constraints can be created with either syntax:

```cypher
-- existence
CREATE CONSTRAINT FOR (n:Author) REQUIRE n.name IS NOT NULL;
CREATE CONSTRAINT ON (n:Author) ASSERT EXISTS (n.name);

-- uniqueness (single and composite)
CREATE CONSTRAINT FOR (n:Book) REQUIRE n.isbn IS UNIQUE;
CREATE CONSTRAINT FOR (n:Book) REQUIRE (n.title, n.year) IS UNIQUE;
CREATE CONSTRAINT ON (n:Book) ASSERT n.isbn IS UNIQUE;

-- type
CREATE CONSTRAINT FOR (n:Movie) REQUIRE n.title IS :: STRING;
CREATE CONSTRAINT ON (n:Movie) ASSERT n.title IS TYPED STRING;
```

Constraint names in the Neo4j-style syntax are parsed but not stored — Memgraph does not have a named index/constraint system, so a `WARNING` notification is emitted to the client when a name is provided. Drops therefore must use the `DROP CONSTRAINT ON (...) ASSERT ...` form rather than `DROP CONSTRAINT <name>`.

Relationship uniqueness, existence, and type constraints are **not** supported and will raise a `SemanticException`.

- [Read more about constraints](https://memgraph.com/docs/fundamentals/constraints)

### Shortest path

In Neo4j, to find the shortest possible path between two nodes, you would use the `shortestPath` algorithm:

```cypher
MATCH p=shortestPath(
(:Person {name:"Keanu Reeves"})-[*]-(:Person {name:"Tom Hanks"})
)
RETURN p
```

Memgraph offers fast deep path traversals as [built-in graph algorithms](https://memgraph.com/docs/advanced-algorithms/deep-path-traversal), including BFS, DFS, WSP, ASP, and KSP 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:

```cypher
MATCH p=(:Person {name:"Keanu Reeves"})-[*BFS]-(:Person {name:"Tom Hanks"})
RETURN p
```

### K shortest paths

In Neo4j, to find K shortest paths between two nodes, you would use the `SHORTEST` algorithm with a number:

```cypher
MATCH p = SHORTEST 3 (start:A)-[:E]->(end:B) 
RETURN p;
```

In Memgraph, you need to first match the source and target nodes, then use the `*KSHORTEST` syntax with a limit:

```cypher
MATCH (start:A), (end:B) 
WITH start, end 
MATCH p=(start)-[:E *KSHORTEST | 3]->(end) 
RETURN p;
```

Note that Memgraph requires both source and target nodes to be matched first using a `WITH` clause before applying the K-shortest paths algorithm.

### NOT label expression
In Neo4j, you can use the `NOT` label expression (`!`):
```cypher
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:
```cypher
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:
```cypher
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](https://memgraph.com/docs/advanced-algorithms/deep-path-traversal#depth-first-search) (DFS) algorithm:
```cypher
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:
```cypher
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:
```cypher
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

#### Patterns in expressions

Patterns in expressions are supported in Memgraph in particular functions, like `exists(pattern)`, and
directly inside the [`EXISTS { }` and `COUNT { }` subquery
expressions](https://memgraph.com/docs/querying/subquery-expressions), which accept a bare pattern.
Memgraph also supports filtering based on patterns, like `MATCH (n) WHERE NOT (n)-->()`.
In other cases, Memgraph does not yet support patterns in functions, e.g. `size((n)-->())` — use
`COUNT { (n)-->() }` instead, which counts the matches without building a list.

### Unsupported expressions

#### Cypher expressions

- Numerical:
  - An octal `INTEGER` literal (starting with `0o`): `0o1372`, `0o5671`
  - A `FLOAT` literal: `Inf`, `Infinity`, `NaN`

#### Conditional expressions (CASE)

- More than one value after `WHEN` operator: 
```cypher
MATCH (n:Person)
RETURN
CASE n.eyes
  WHEN 'blue'  THEN 1
  WHEN 'brown', 'hazel' THEN 2
  ELSE 3
END AS result, n.eyes
```
  Here is a workaround in Memgraph:
```cypher
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;
```
  -> Track progress on [GitHub](https://github.com/memgraph/memgraph/issues/1853) and add a comment if you require such a feature.

#### Type predicate expressions

The following expression is not supported in Memgraph:
```cypher
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](https://memgraph.com/docs/querying/functions#scalar-functions), which returns the value type of the object in textual format:
```cypher
UNWIND [42, true, 'abc'] AS val
RETURN val, valueType(val) = "INTEGER"
```

### Unsupported functions

**Predicate functions**:

- `exists(n.property)` - can be expressed using `n.property IS NOT NULL`
- `isEmpty()`

**Scalar functions**:

- `nullIf()`

**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:

- [Deep path traversals](https://memgraph.com/docs/advanced-algorithms/deep-path-traversal)
- [`ANALYZE GRAPH`](https://memgraph.com/docs/fundamentals/indexes#analyze-graph)
- [`DROP GRAPH`](https://memgraph.com/docs/querying/clauses/drop-graph)
- [MAGE algorithms library](https://memgraph.com/docs/advanced-algorithms)
- [Custom query modules](https://memgraph.com/docs/custom-query-modules)
- [`ALTER`](https://memgraph.com/docs/querying/clauses/alter)
- [`USING PARALLEL EXECUTION`](https://memgraph.com/docs/querying/clauses/using-parallel-execution)

> **Info**
>
> For all other unsupported constructs that you require, please open an issue on our [GitHub repository](https://github.com/memgraph/memgraph/issues).
