Migrating from Neo4j to SurrealDB

This page details some Neo4j data types and patterns in the Cypher query language along with their SurrealQL equivalents or near equivalents, followed by links to the Surreal Sync tool which allows data from Neo4j to be automatically imported to SurrealDB.

Concept mapping

Neo4jSurrealDB
database database
node label table
node record
node property field
index index
id record id
transactions transactions
relationships record links, embedding and graph relations

Data types

The following chart shows Neo4j data types along with the equivalent or near-equivalent SurrealQL data type for each.

Neo4j Data TypeSurrealDB MappingNotes
Booleanbool
Integerint
Floatfloat (f64)
Stringstring
Listarray
Mapobject
Nullnull
DatedatetimeConvert to UTC datetime (assuming local timezone)
DateTimedatetimeConvert to UTC datetime
LocalDateTimedatetimeConvert to UTC datetime (assuming UTC)
Durationduration
Bytesbytes
TimeobjectConvert to object with type: "$Neo4jTime", hour, minute, second, nanosecond, offset_seconds fields
LocalTimeobjectConvert to object with type: "$Neo4jLocalTime", hour, minute, second, nanosecond fields
Point2DobjectConvert to GeoJSON-like object with type: "Point", srid (4326), coordinates: [longitude, latitude]
Point3DobjectConvert to GeoJSON-like object with type: "Point", srid (4979), coordinates: [longitude, latitude, elevation]
DateTimeZoneIddatetimeConvert to UTC datetime using embedded timezone ID

Syntax mapping

The following shows some CRUD examples using SurrealQL syntax.

Create

As Neo4j is schemaless, only the SurrealQL schemaless approach is shown below. For a schemafull option see the DEFINE TABLE page.

For more SurrealQL examples, see the CREATE, INSERT and RELATE pages.

Simple create/insert operations:

// Cypher
CREATE (John:Person {name:‘John’}), (Jane:Person {name: ‘Jane})

// SurrealQL
// Table implicitly created if it doesn't exist
INSERT INTO person [ {id: “John”, name: “John}, {id: “Jane”, name: “Jane} ]

Graph relations via the RELATE statement:

// Cypher
MATCH (p:Person {name:‘Jane}), (pr:Product {name:‘iPhone}) CREATE (p)-[:ORDER]->(pr)

// SurrealQL
RELATE person:Jane->order->product:iPhone

Defining an index:

// Cypher
CREATE INDEX personNameIndex FOR (p:Person) ON (p.name)

// SurrealQL
DEFINE INDEX idx_name ON TABLE person COLUMNS name

Read

For more SurrealQL examples, see the SELECT, LIVE SELECT and RETURN pages.

Returning all the fields of a table:

// Cypher
MATCH (p:Person) RETURN p

// SurrealQL
SELECT * FROM person

Returning a single field of a table:

// Cypher
MATCH (p:Person) RETURN p.name

// SurrealQL
SELECT name FROM person

Using the WHERE clause to return certain records:

// Cypher
MATCH (p:Person) WHERE p.name =Jane” RETURN p.name

// SurrealQL
SELECT name FROM person WHERE name =Jane

Using EXPLAIN to detail the query plan used:

// Cypher
EXPLAIN MATCH (p:Person) WHERE p.name = "Jane" RETURN p.name

// SurrealQL
SELECT name FROM person WHERE name = "Jane" EXPLAIN

Grouping and counting the number of records returned:

// Cypher
MATCH (p:Person) RETURN count(*) as person_count

// SurrealQL
SELECT count() AS person_count FROM person GROUP ALL

See all distinct values for a field among the records of a table:

// Cypher
MATCH (p:Person) RETURN distinct p.name

// SurrealQL
SELECT array::distinct(name) FROM person GROUP ALL

Returning up to a certain number of records:

// Cypher
MATCH (p:Person) RETURN p LIMIT 10

// SurrealQL
SELECT * FROM person LIMIT 10

See which person records have ordered a product via the order graph edge:

// Cypher
MATCH (p:Person)-[:ORDER]->(pr:Product) RETURN p.name, pr.name

// SurrealQL
SELECT name, ->order->product.name FROM person

Update

For more SurrealQL examples, see the UPDATE page.

Conditionally updating records that have a certain value for a field:

// Cypher
MATCH (p:Person) WHERE p.name = "Jane" SET p.last_name = 'Doe' RETURN p

// SurrealQL
UPDATE person SET last_name = "Doe" WHERE name = "Jane"

Unsetting (removing) the value of a field for certain records:

// Cypher
MATCH (p:Person) WHERE p.name = "Jane" REMOVE p.last_name RETURN p

// SurrealQL
UPDATE person UNSET last_name WHERE name = "Jane"

Delete

For more SurrealQL examples, see the DELETE and REMOVE pages.

Conditionally deleting records based on the value of a field:

// Cypher
MATCH (p:Person) WHERE p.name = "Jane" DELETE p

// SurrealQL
DELETE person WHERE name = "Jane"

Deleting all records for a table (SurrealQL: table still exists):

// Cypher
MATCH (p:Person) DELETE p

// SurrealQL
DELETE person

Deleting all records and table definition for a table:

// Cypher
MATCH (p:Person) DELETE p

// SurrealQL
REMOVE TABLE person

Importing from Neo4j using Surreal Sync

Surreal Sync can be used to export Neo4j nodes and relationships to SurrealDB.

It supports inconsistent full syncs and consistent incremental syncs, and together provides ability to reproduce consistent snapshots from the source Neo4j graph onto the target SurrealDB tables.

For more on how to import data from Neo4j to SurrealDB, please see the following pages in the Surreal Sync repo.