The Cypher Query Language - Best Practices
Tags: memgraph, cypher
Published: 2021-10-20 06:31:59

**Cypher**, like any other programming or query language, has a defined set of rules for writing readable and well-designed constructs. By following this guide, you will learn how to format and organize Cypher queries so that naming conventions and formatting are consistent and understandable to everyone. 

Don't worry if you are still new to graph databases or Cypher. Most example queries are very easy to understand just from context and don't require any advanced knowledge. 

## Data model styling

Defining your data model is one of the most important steps when it comes to styling. Because these constructs will be used throughout your whole project, it would be very wise to think about the naming convention and formatting rules before committing to specific ones. 
**Sticking to shared best practices** is by far the **best choice** because it enables other users to easily read and understand your data model and queries. In this section, you'll find recommendations on how to name nodes and relationships, their properties, variables... and so on. 

### Nodes

When it comes to nodes, the most important factor is styling labels. Node labels should be defined in **CamelCase**, which means that the first letter of each word begins with a capital letter. Because Cypher is case-sensitive, it is important to uphold this style throughout every query you write.

```cypher
(:Country)
(:City)
(:CapitalCity)
```

### Relationships

Relationship types are styled upper-case and use the underscore character `_` to separate multiple words.

```cypher
[:LIVES_IN]
(:BORDERS_WITH)
```

### Properties, variables, parameters, aliases, and functions

Property keys, variables, parameters, aliases, and functions should have a  **camelCase** style where the first letter of the word is lower-case, and the first letter of each following word is a capital letter. All of these constructs are case-sensitive, so capitalization must match either what is in the database (properties), what is already defined in the query (variables, parameters, aliases), or Cypher definitions (functions).

```cypher
dateOfBirth // Property key
largestCountry // Variable
size() // Function
countryOne // Alias
```

### Clauses

Clauses should be defined with capital letters, even if they consist of two or more words. Each new clause should be placed at the beginning of a new line to ensure complete readability. While clauses are not case sensitive, we strongly discourage you from using any other style to avoid confusion.

```cypher
MATCH (c:Country)
WHERE c.name = 'UK'
RETURN c;

WITH "2021-01-01" as currentDate
MATCH (p:Person)
WHERE p.birthdate > currentDate
RETURN p.name;
```

### Keywords

Aside from clauses, there is a number of keywords that should be in upper case even though they are not case sensitive. These include: `DISTINCT`, `IN`, `STARTS WITH`, `CONTAINS`, `NOT`, `AND`, `OR` and `AS`.

```cypher
MATCH (c:Country)
WHERE c.name CONTAINS 'United' AND c.population > 9000000
RETURN c AS Country;
```

## Indentations and line breaks

Sometimes it's helpful to separate new clauses with an indent. Even though they are in a new line, subqueries should be indented to ensure readability.
If there are multiple subqueries, they can be further grouped by using curly brackets.

```cypher
//Indent 2 spaces on lines with ON CREATE or ON MATCH subqueries
MATCH (p:Person {name: 'Helga'})
MERGE (c:Country {name: 'UK'})
MERGE (p)-[l:LIVES_IN]->(c)
  ON CREATE SET l.movedIn = date({year: 2020})
  ON MATCH SET l.modified = date()
RETURN p, l, c;

//Indent 2 spaces with braces for subqueries
MATCH (p:Person)
WHERE EXISTS {
  MATCH (p)-->(c:Country)
  WHERE c.name = 'UK'
}
RETURN p;
```

An exception to this rule would be a one-line subquery where you don't need to use a new line or an indent.

```cypher
MATCH (p:Person)
WHERE EXISTS { MATCH (p)-->(c:Country {name: 'UK'}) }
RETURN p
```

## Metacharacters

### Quotes

When it comes to quotes, a simple rule is to use whichever provides the fewest escaped characters in the string. If escaped characters are not needed or their number is the same for both single and double quotes, then single quotes should be favored. 

```cypher
// Bad syntax
RETURN 'Memgraph\'s mission is: ', "A very famous quote is: \"Astra inclinant, sed non obligant.\""

// Recommended syntax
RETURN "Memgraph's mission is: ", 'A very famous quote is: "Astra inclinant, sed non obligant."'
```

### Semicolons

In most cases, a semicolon at the end of a Cypher query is unnecessary. The exception is when you have a script or a block with multiple separate Cypher queries that should be executed independently. 

```cypher
MATCH (c:Country {name: 'UK'})
RETURN c;

MATCH (c:Country {name: 'Germany'})
RETURN c;
```

## Null and Boolean Values

Boolean literals and `null` values should always be lower case.

```cypher
// Bad syntax
MATCH (c:Country)
WHERE c.island = NULL
  SET islandCountry = True
RETURN c

// Recommended syntax
MATCH (c:Country)
WHERE c.island = null
  SET islandCountry = true
RETURN c
```

## Pattern styling 

* When you have a pattern that is too long for one line, the recommended practice is to break after an arrow, not before it.

```cypher
// Bad syntax
MATCH (:Country)-->(:Person)-->(:Person)
      <--(c:Country)
RETURN c.name

// Recommended syntax
MATCH (:Country)-->(:Person)-->(:Person)<--
      (c:Country)
RETURN c.name
```

* If you don't plan on using a variable in the query, it's better to use anonymous nodes and relationships instead.

```cypher
// Bad syntax
MATCH (c:Country {name: 'UK'})<-[l:LIVES_IN]-(p:Person)
RETURN p.name

// Recommended syntax
MATCH (:Country {name: 'UK'})<-[:LIVES_IN]-(p:Person)
RETURN p.name
```

* Nodes with assigned variables should come before anonymous nodes and relationships if possible. The same goes for nodes that are starting points or the central focus of the query.

```cypher
// Bad syntax
MATCH (:Person)-[:LIVES_IN]->(c:Country {name: 'UK'})
RETURN c

// Recommended syntax
MATCH (c:Country {name: 'UK'})<-[:LIVES_IN]-(:Person)
RETURN c
```

* Patterns should be ordered so that left-to-right relationships (arrows) come at the beginning of the query. 

```cypher
// Bad syntax
MATCH (c:Country)<-[:BORDERS_WITH]-(:Country)<-[:LIVES_IN]-(:Person)
RETURN c

// Recommended syntax
MATCH (:Person)-[:LIVES_IN]->(:Country)-[:BORDERS_WITH]->(c:Country)
RETURN c
```

## Spacing

Spacing has a big impact on the readability of queries. Some of the recommended practices when it comes to spacing are:

* There should be one space between property predicates and label/type predicates.

```cypher
// Bad syntax
MATCH (:Country   {name: 'UK'})<-[:LIVES_IN{since: 2010}]-(p:Person)
RETURN p.name

// Recommended syntax
MATCH (:Country {name: 'UK'})<-[:LIVES_IN {since: 2010}]-(p:Person)
RETURN p.name
```

* There should be no spaces in label predicates.

```cypher
// Bad syntax
MATCH (c: Country:  City)
RETURN c.name

// Recommended syntax
MATCH (c:Country:City)
RETURN c.name
```

* There should be no spaces in patterns.

```cypher
// Bad syntax
MATCH (c:Country) --> (:City) 
RETURN c.name

// Recommended syntax
MATCH (c:Country)-->(:City) 
RETURN c.name
```

* There should be one space on both sides of an operator. 

```cypher
// Bad syntax
MATCH (c:Country)
WHERE population>100000
RETURN c.name

// Recommended syntax
MATCH (c:Country)
WHERE population > 100000
RETURN c.name
```

* There should be one space between elements in a list (after each comma).

```cypher
// Bad syntax
WITH ['UK','US','Germany'] as list
MATCH (c:Country)
WHERE c.name IN list
RETURN c.name

// Recommended syntax
WITH ['UK', 'US', 'Germany'] as list
MATCH (c:Country)
WHERE c.name IN list
RETURN c.name
```

* Function call parentheses should only have one space after each comma.

```cypher
// Bad syntax
RETURN split( 'A', 'B' , 'C' )

// Recommended syntax
RETURN split('A', 'B', 'C')
```

* Map literals should only have one space after each comma and one space separating a colon and a value.

```cypher
// Bad syntax
WITH { name :'UK' ,population  :  70000000 } AS country
RETURN country

// Recommended syntax
WITH {name: 'UK', population: 70000000} AS country
RETURN country
```

## Conclusion 

Having a well-defined style for writing queries is a technical must-have. It makes it easier and faster to understand queries that other people have written while also enabling everyone to contribute in a meaningful way without having to worry about the format. Whenever you are not sure about a naming convention or the structure of your query, just take a quick look at this guide. 

If you have trouble writing a specific query or would just like to learn about the concepts that are available in Cypher, go through our [Cypher Cheat Sheet](https://memgraph.com/blog/cypher-cheat-sheet).