Data types and mapping to Cypher types

The tables in this section show the mapping between Cypher data types and JavaScript types.

Core types

Cypher Type JavaScript Type

NULL

null

LIST

Array

MAP

Object

BOOLEAN

Boolean

INTEGER

Integer

FLOAT

Number

STRING

String

ByteArray

Int8Array

Integer is not one of JavaScript’s native types, but rather a custom one accomodating Cypher’s precision. You can disable this through the disableLosslessIntegers configuration entry when instantiating the driver, so that JavaScript’s native Number type is used instead. Note that this can lead to a loss of precision.

Temporal types

Temporal data types are ISO-8601-compliant. To serialize them to string, use the .toString() method. Temporal objects are immutable.

Sub-second values are measured to nanosecond precision. To convert between driver and native types, use the methods .fromStandardDate() and .toStandardDate() (does not apply to Duration). Since JavaScript date types do not support nanoseconds, .fromStandardDate() allows a nanoseconds argument (optional), and .toStandardDate() drops the nanoseconds.

For a list of time zone abbreviations, see List of tz database time zones.

Cypher Type JavaScript Type

DATE

Date

ZONED TIME

Time

LOCAL TIME

LocalTime

ZONED DATETIME

DateTime

LOCAL DATETIME

LocalDateTime

DURATION

Duration

How to use temporal types in queries
const neo4j = require('neo4j-driver');
const URI = '<URI for Neo4j database>';
const USER = '<Username>';
const PASSWORD = '<Password>';

(async () => {
  const driver = neo4j.driver(URI, neo4j.auth.basic(USER, PASSWORD))

  const friendsSince = new neo4j.types.DateTime(1999, 11, 23, 7, 47, 0, 4123, -4*3600, 'Europe/Berlin')

  // JS native types work as well.
  // They don't support the full feature-set of Neo4j's type though.
  // let jsFriendsSince = new Date(1999, 11, 23, 7, 47, 0)
  // jsFriendsSince = new neo4j.types.Date.fromStandardDate(jsFriendsSince)

  // Create a friendship with the given DateTime, and return the DateTime
  const result = await driver.executeQuery(`
    MERGE (a:Person {name: $name})
    MERGE (b:Person {name: $friend})
    MERGE (a)-[friendship:KNOWS]->(b)
    SET friendship.since = $friendsSince
    RETURN friendship.since
    `, {
      name: 'Alice', friend: 'Bob',
      friendsSince: friendsSince  // or friendsSince: jsFriendsSince
    }
  )
  const outDateTime = result.records[0].get('friendship.since')
  console.log(outDateTime)
  /*
  DateTime {
    year: Integer { low: 1999, high: 0 },
    month: Integer { low: 11, high: 0 },
    day: Integer { low: 23, high: 0 },
    hour: Integer { low: 6, high: 0 },
    minute: Integer { low: 47, high: 0 },
    second: Integer { low: 0, high: 0 },
    nanosecond: Integer { low: 4123, high: 0 },
    timeZoneOffsetSeconds: Integer { low: -18000, high: -1 },
    timeZoneId: 'Europe/Berlin'
  }
 */

  // Convert DateTime to JS native Date (lossy)
  const jsOutDateTime = outDateTime.toStandardDate()
  console.log(jsOutDateTime)
  // 1999-11-23T11:47:00.000Z

  await driver.close()
})()

Date

Represents an instant capturing the date, but not the time, nor the timezone.

d = new neo4j.Date(2021, 11, 2)
// Date { year: 2021, month: 11, day: 2 }
d.toString() // '2021-11-02'

For full documentation, see API documentation — Date.

Time

Represents an instant capturing the time, and the timezone offset in seconds, but not the date.

d = new neo4j.Time(7, 47, 0, 4123, -4*3600)
/*
Time {
  hour: 7,
  minute: 47,
  second: 0,
  nanosecond: 4123,
  timeZoneOffsetSeconds: -14400
}
*/
d.toString() // '07:47:00.000004123-04:00'

For full documentation, see API documentation — Time.

LocalTime

Represents an instant capturing the time of day, but not the date, nor the timezone.

d = new neo4j.LocalTime(7, 47, 0, 4123)
// LocalTime { hour: 7, minute: 47, second: 0, nanosecond: 4123 }
d.toString() // '07:47:00.000004123'

For full documentation, see API documentation — LocalTime.

DateTime

Represents an instant capturing the date, the time, and the timezone identifier. Timezone parameters (offset and identifier) are optional.

d = new neo4j.DateTime(2021, 11, 2, 7, 47, 0, 4123, -4*3600, 'Europe/Berlin')
/*
DateTime {
  year: 2021,
  month: 11,
  day: 2,
  hour: 7,
  minute: 47,
  second: 0,
  nanosecond: 4123,
  timeZoneOffsetSeconds: -14400,
  timeZoneId: 'Europe/Berlin'
}
*/
d.toString() // '2021-11-02T07:47:00.000004123-04:00[US/Eastern]'

For full documentation, see API documentation — DateTime.

LocalDateTime

Represents an instant capturing the date and the time, but not the timezone.

d = new neo4j.LocalDateTime(2021, 11, 2, 7, 47, 0, 4123)
/*
LocalDateTime {
  year: 2021,
  month: 11,
  day: 2,
  hour: 7,
  minute: 47,
  second: 0,
  nanosecond: 4123
}
*/
d.toString() // '2021-11-02T07:47:00.000004123'

For full documentation, see API documentation — LocalDateTime.

Duration

Represents the difference between two points in time.

const d = new neo4j.Duration(1, 2, 3, 4)
/*
Duration {
  months: 1,
  days: 2,
  seconds: Integer { low: 3, high: 0 },
  nanoseconds: Integer { low: 4, high: 0 }
}
*/
d.toString() // 'P1M2DT3.000000004S'

For full documentation, see API documentation — Duration.

Spatial types

Cypher supports spatial values (points), and Neo4j can store these point values as properties on nodes and relationships.

The driver has a single type neo4j.types.Point, which can behave as a 2D/3D cartesian/WGS-84 point, depending on the SRID it is initialized with. The SRID (short for Spatial Reference Identifier) is a number identifying the coordinate system the point is to be interpreted in. You can think of it as a unique identifier for each spatial type.

SRID Description

7203

2D point in the cartesian space.

9157

3D point in the cartesian space.

4326

2D point in the WGS84 space.

4979

3D point in the WGS84 space.

Points in cartesian space
// A 2D Point in cartesian space
const point2d = new neo4j.types.Point(
  7203, // SRID
  1, // x
  5.1 // y
)
// Point { srid: 4979, x: 1, y: -2 }

// A 3D Point in cartesian space
const point3d = new neo4j.types.Point(
  9157, // SRID
  1, // x
  -2, // y
  3.1 // z
)
// Point { srid: 4979, x: 1, y: -2, z: 3.1 }
Points in WGS-84 space
// A 2D point in WGS-84 space
const point2d = new neo4j.types.Point(
  4326, // SRID
  1, // x
  -2, // y
  3.1 // z
)
// Point { srid: 4979, x: 1, y: -2}

// A 3D point in WGS-84 space
const point3d = new neo4j.types.Point(
  4979, // SRID
  1, // x
  -2, // y
  3.1 // z
)
// Point { srid: 4979, x: 1, y: -2, z: 3.1 }

For full documentation, see API documentation — Point.

Graph types

Graph types are only passed as results and may not be used as parameters.

Cypher Type JavaScript Type

NODE

neo4j.types.Node

RELATIONSHIP

neo4j.types.Relationship

PATH

neo4j.types.Path

neo4j.types.PathSegment

Node

Represents a node in a graph.
The property elementId provides an identifier for the entity. This should be used with care, as no guarantees are given about the mapping between id values and elements outside the scope of a single transaction. In other words, using an elementId to MATCH an element across different transactions is risky.

const neo4j = require('neo4j-driver');
const URI = '<URI for Neo4j database>';
const USER = '<Username>';
const PASSWORD = '<Password>';

(async () => {
  const driver = neo4j.driver(URI, neo4j.auth.basic(USER, PASSWORD))
  const result = await driver.executeQuery(
    'MERGE (p:Person {name: $name}) RETURN p AS person',
    { name: 'Alice' }
  )
  const node = result.records[0].get('person')
  console.log(node)
  /*
  Node {
    identity: Integer { low: 393, high: 0 },  // deprecated
    labels: [ 'Person' ],
    properties: { name: 'Alice' },
    elementId: '4:d6154461-ff34-42a9-b7c3-d32673913419:393'
  }
  */
  await driver.close()
})()

For full documentation, see API documentation — Node.

Relationship

Represents a relationship in a graph.
The property elementId provides an identifier for the entity. This should be used with care, as no guarantees are given about the mapping between id values and elements outside the scope of a single transaction. The same applies to startNodeElementId and endNodeElementId.

const neo4j = require('neo4j-driver');
const URI = '<URI for Neo4j database>';
const USER = '<Username>';
const PASSWORD = '<Password>';

(async () => {
  const driver = neo4j.driver(URI, neo4j.auth.basic(USER, PASSWORD))
  const result = await driver.executeQuery(`
    MERGE (p:Person {name: $name})
    MERGE (friend:Person {name: $friend_name})
    MERGE (p)-[r:KNOWS]->(friend)
    SET r.status = $status, r.since = date()
    RETURN r AS friendship
    `, {
      name: 'Alice', status: 'BFF', friend_name: 'Bob'
    }
  )
  const relationship = result.records[0].get('friendship')
  console.log(relationship)
  /*
  Relationship {
    identity: Integer { low: 388, high: 0 },  // deprecated
    start: Integer { low: 393, high: 0 },  // deprecated
    end: Integer { low: 394, high: 0 },  // deprecated
    type: 'KNOWS',
    properties: {
      since: Date { year: [Integer], month: [Integer], day: [Integer] },
      status: 'BFF'
    },
    elementId: '5:d6154461-ff34-42a9-b7c3-d32673913419:388',
    startNodeElementId: '4:d6154461-ff34-42a9-b7c3-d32673913419:393',
    endNodeElementId: '4:d6154461-ff34-42a9-b7c3-d32673913419:394'
  }
  */
  await driver.close()
})()

For full documentation, see API documentation — Relationship.

Path, PathSegment

Path represents a path in a graph, while PathSegment represents its individual links.

const neo4j = require('neo4j-driver');
const URI = '<URI for Neo4j database>';
const USER = '<Username>';
const PASSWORD = '<Password>';

(async () => {
  const driver = neo4j.driver(URI, neo4j.auth.basic(USER, PASSWORD))

  // Create some :Person nodes linked by :KNOWS relationships
  await addFriend(driver, 'Alice', 'BFF', 'Bob')
  await addFriend(driver, 'Bob', 'Fiends', 'Sofia')
  await addFriend(driver, 'Sofia', 'Acquaintances', 'Sara')

  // Follow :KNOWS relationships outgoing from Alice three times, return as path
  const result = await driver.executeQuery(`
    MATCH p = (:Person {name: $name})-[:KNOWS*3]->(:Person)
    RETURN p AS friendsChain
    `, {
      name: 'Alice'
    }
  )
  const path = result.records[0].get('friendsChain')
  console.log(path)
  /*
  Path {
    start: Node {
      identity: Integer { low: 393, high: 0 },
      labels: [ 'Person' ],
      properties: { name: 'Alice' },
      elementId: '4:d6154461-ff34-42a9-b7c3-d32673913419:393'
    },
    end: Node {
      identity: Integer { low: 396, high: 0 },
      labels: [ 'Person' ],
      properties: { name: 'Sara' },
      elementId: '4:d6154461-ff34-42a9-b7c3-d32673913419:396'
    },
    segments: [
      PathSegment {
        start: [Node],
        relationship: [Relationship],
        end: [Node]
      },
      PathSegment {
        start: [Node],
        relationship: [Relationship],
        end: [Node]
      },
      PathSegment {
        start: [Node],
        relationship: [Relationship],
        end: [Node]
      }
    ],
    length: 3
  }
  */
  await driver.close()
})()

async function addFriend(driver, name, status, friendName) {
  await driver.executeQuery(`
    MERGE (p:Person {name: $name})
    MERGE (friend:Person {name: $friendName})
    MERGE (p)-[r:KNOWS]->(friend)
    SET r.status = $status, r.since = date()
    `, {
      name: name, status: status, friendName: friendName
    }
  )
}

For full documentation, see API documentation — Path and PathSegment.

Errors

All errors raised by the driver are of type Neo4jError. For a list of errors the server can return, see the Status code page.

Some server errors are marked as safe to retry without need to alter the original request. Examples of such errors are deadlocks and memory issues. All driver’s exception types implement the method .isRetryable(), which gives insights into whether a further attempt might be successful. This is particular useful when running queries in explicit transactions, to know if a failed query should be run again.

Glossary

LTS

A Long Term Support release is one guaranteed to be supported for a number of years. Neo4j 4.4 is LTS, and Neo4j 5 will also have an LTS version.

Aura

Aura is Neo4j’s fully managed cloud service. It comes with both free and paid plans.

Cypher

Cypher is Neo4j’s graph query language that lets you retrieve data from the database. It is like SQL, but for graphs.

APOC

Awesome Procedures On Cypher (APOC) is a library of (many) functions that can not be easily expressed in Cypher itself.

Bolt

Bolt is the protocol used for interaction between Neo4j instances and drivers. It listens on port 7687 by default.

ACID

Atomicity, Consistency, Isolation, Durability (ACID) are properties guaranteeing that database transactions are processed reliably. An ACID-compliant DBMS ensures that the data in the database remains accurate and consistent despite failures.

eventual consistency

A database is eventually consistent if it provides the guarantee that all cluster members will, at some point in time, store the latest version of the data.

causal consistency

A database is causally consistent if read and write queries are seen by every member of the cluster in the same order. This is stronger than eventual consistency.

NULL

The null marker is not a type but a placeholder for absence of value. For more information, see Cypher → Working with null.

transaction

A transaction is a unit of work that is either committed in its entirety or rolled back on failure. An example is a bank transfer: it involves multiple steps, but they must all succeed or be reverted, to avoid money being subtracted from one account but not added to the other.

backpressure

Backpressure is a force opposing the flow of data. It ensures that the client is not being overwhelmed by data faster than it can handle.

transaction function

A transaction function is a callback executed by an executeRead or executeWrite call. The driver automatically re-executes the callback in case of server failure.

Driver

A Driver object holds the details required to establish connections with a Neo4j database.