Skip to content
Part IA Michaelmas Term

Neo4j and Cypher

Neo4j overview

Neo4j is a Java-based graph-oriented DBMS. It stores data as nodes and directed edges, both with types, labels, and properties. The native query language is Cypher (named after a character in The Matrix). Data is typically imported from external sources rather than entered interactively.

Creating nodes

Nodes are created with the CREATE statement. The syntax (identifier:Type {properties}) specifies a node:

CREATE (nm0000102:Person {name: 'Kevin Bacon', birthyear: 1958})
  • nm0000102 is a variable name used within the query to refer to this node. It is not stored — it is a temporary handle for the duration of the current Cypher statement.
  • Person is the type.
  • The key-value pairs are properties.

Creating edges

Edges are created using an arrow syntax between two nodes:

CREATE (nm0002002)-[:ACTED_IN {role: 'James Bond'}]->(tt0299478)

This assumes nm0002002 and tt0299478 already exist (they would have been created in earlier CREATE statements). The edge:

  • Has type ACTED_IN.
  • Has property role with value 'James Bond'.
  • Is directed from the actor node to the movie node.

Nodes and edges both use the <variable name>:<type> syntax. All edges have a stored direction.

Graph data normalisation: modelling decisions

Modelling decisions matter in a graph database, just as they do in a relational one. Consider a film database.

Poor design — using the role name as the edge type:

(nm0000084)-[:SU_LI_ZHEN]->(tt0212712)

This is problematic for two reasons:

  1. Edge type names must be unique identifiers. The same role name might appear in remakes with different actors.
  2. It conflates a property of the relationship (the character played) with the type of the relationship (that it is a performance).

Better design — using a generic edge type and storing the role as a property:

(nm0000084)-[:PLAYS_ROLE {role: 'Su Li-zhen'}]->(tt0212712)

Now PLAYS_ROLE is the reusable edge type, and the specific character name is data. This distinction is the graph equivalent of choosing between an attribute and a separate relation in the E/R model.

Property types

Neo4j supports a limited set of property types: integers, floats, strings, booleans, and arrays of these. There is no date type, no decimal/numeric type, and no branded types. Dates are conventionally stored as formatted strings (ISO 8601), which loses type safety.

Importing data

Neo4j is not typically used for data entry. Data is imported in bulk from CSV, JSON, or other structured sources. The LOAD CSV command reads external files:

LOAD CSV WITH HEADERS FROM 'file:///people.csv' AS row
CREATE (:Person {name: row.name, birthyear: toInteger(row.birthyear)})

This batch-loading pattern is common: graphs are derived from existing datasets rather than built up interactively.

Comparison to SQL

AspectSQL (DDL + DML)Cypher
Node/row creationINSERT INTO T VALUES (...)CREATE (:Type {key: val})
Edge/relationshipForeign key constraint + join tableCREATE (a)-[:TYPE]->(b)
Schema enforcementStrong; CREATE TABLE defines columnsWeak; node types are informal
Path traversalRecursive CTE()-[:TYPE*]->()

Summary

  • Neo4j stores typed, labelled, directed graphs with key-value properties on nodes and edges.
  • Cypher uses CREATE for both nodes and edges, with (:Type {props}) and -[:Type {props}]-> syntax.
  • Good modelling separates the edge type (what kind of relationship) from edge properties (the data about a particular instance of that relationship).
  • Data is typically bulk-imported from external sources rather than entered interactively.
  • Neo4j has no built-in date type; dates are stored as strings.