Data types

Data types

Since Memgraph is a graph database management system, data is stored in the form of graph objects: nodes and relationships. Each graph object can contain various types of data. This page describes which data types are supported in Memgraph.

Node labels & relationship types

Nodes can have labels that are used to label or group nodes. A label is of the type String, and each node can have none or multiple labels. Labels can be changed at any time.

Relationships have a type, also represented in the form of a String. Unlike nodes, relationships must have exactly one relationship type and once it is set upon creation, it can never be modified again.

Property types

Nodes and relationships can store various properties. Properties are similar to mappings or tables containing property names and their accompanying values. Property names are represented as text, while values can be of different types.

Each property can store a single value, and it is not possible to have multiple properties with the same name on a single graph element. But, the same property names can be found across multiple graph elements.

Also, there are no restrictions on the number of properties that can be stored in a single graph element. The only restriction is that the values must be of the supported types. Below is a table of supported data types.

TypeDescription
NullProperty has no value, which is the same as if the property doesn't exist.
StringA character string (text).
BooleanA boolean value, either true or false.
IntegerAn integer number.
FloatA floating-point number (real number).
ListA list containing any number of property values of any supported type under a single property name.
MapA mapping of string keys to values of any supported type.
DurationA period of time.
DateA date with year, month, and day.
LocalTimeTime without the timezone.
LocalDateTimeDate and time without the timezone.
ZonedDateTimeDate and time in a specific timezone.
EnumAn enumeration value.
Point2D or 3D point either in Cartesian or WGS format.

If you want to modify List and Map property values, you need to replace them entirely.

The following queries are valid:

CREATE (:Node {property: [1, 2, 3]});
CREATE (:Node {property: {key: "value"}});

But these are not:

MATCH (n:Node) SET n.property[0] = 0;
MATCH (n:Node) SET n.property.key = "other value";

Maps

The Cypher query language supports constructing and working with map values.

Literal maps

It is possible to explicitly construct maps by stating key-value pairs:

For example:

RETURN {key: 'Value', listKey: [{inner: 'Map1'}, {inner: 'Map2'}]}
┌─────────────────────────────────────────────────────────────┐
│ {key: 'Value', listKey: [{inner: 'Map1'}, {inner: 'Map2'}]} │
├─────────────────────────────────────────────────────────────┤
│ {Map} 2 properties                                          │
│ {                                                           │
│   "key": "Value",                                           │
│   "listKey": [                                              │
│       {                                                     │
│         "inner": "Map1"                                     │
│       },                                                    │
│       {                                                     │
│         "inner": "Map2"                                     │
│       }                                                     │
│   ]                                                         │
│ }                                                           │
└─────────────────────────────────────────────────────────────┘

Map projection

Cypher’s map projection syntax allows constructing map projections from nodes, relationships, other map values, and all the other values that have properties.

A map projection begins with the variable bound to the graph entity that’s to be projected from, and contains a body of comma-separated map elements enclosed by { and }.

map_variable {map_element, [, ...n]}

A map element projects one or more key-value pairs to the map projection. There are four different types of map projection elements:

  1. Property selector: Projects the property name as the key, and the value of map_variable.property as the value for the projection.
  2. All-properties selector: Projects all key-value pairs from the map_variable value.
  3. Literal entry: This is a key-value pair, with the value being an arbitrary expression: key: <expression>.
  4. Variable selector: Projects a variable: the variable name is the key, and the value it is pointing to is the value of the projection: <variable>.

The following conditions apply:

  • If map_variable points to a null value, its projected values will be null.
  • As with literal maps, key names must be strings.

Examples

The following graph is used by all the examples below:

Example 1

Find a Person node named Jennifer Lawrence and return data about her and the movies she’s acted in. This example contains a map projection with a literal entry, which in turn also uses map projection inside collect().

MATCH (actor:Person {name: 'Jennifer Lawrence'})-[:ACTED_IN]->(movie:Movie)
WITH actor, collect(movie {.title, .year}) AS movies
RETURN actor {.name, roles: movies} AS jennifer
┌─────────────────────────────────────────────────────────────┐
│ jennifer                                                    │
├─────────────────────────────────────────────────────────────┤
│ {Map} 3 properties                                          │
│ {                                                           │
│   "name": "Jennifer Lawrence",                              │
│   "roles": [                                                │
│       {                                                     │
│         "year": 2012,                                       │
│         "title": "Silver Linings Playbook"                  │
│       },                                                    │
│       {                                                     │
│         "year": 2013,                                       │
│         "title": "American Hustle"                          │
│       },                                                    │
│       {                                                     │
│         "year": 2015,                                       │
│         "title": "Joy"                                      │
│       },                                                    │
│       {                                                     │
│         "year": 2021,                                       │
│         "title": "Don’t Look Up"                            │
│       }                                                     │
│   ]                                                         │
│ }                                                           │
└─────────────────────────────────────────────────────────────┘

Example 2

The query below finds all Person nodes that have one or more ACTED_IN relationships connected to the Movie nodes and returns the number of movies each Person has starred in. This example introduces the variable selector and uses it to project the movie count.

MATCH (actor:Person)-[:ACTED_IN]->(movie:Movie)
WITH actor, count(movie) AS nMovies
RETURN actor {.name, nMovies}
┌─────────────────────────────────────────────────────────────┐
│ actor {.name, nMovies}                                      │
├─────────────────────────────────────────────────────────────┤
│ {Map} 2 properties                                          │
│ {                                                           │
│    "name": "Jennifer Lawrence",                             │
│    "nMovies": 4                                             │
│ }                                                           │
├╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌┤
│ {Map} 2 properties                                          │
│ {                                                           │
│    "name": "Bradley Cooper",                                │
│    "nMovies": 4                                             │
│ }                                                           │
└─────────────────────────────────────────────────────────────┘

Example 3

The following query returns all properties from the Bradley Cooper node. It uses an all-properties selector to project node properties, and in addition explicitly projects the dateOfBirth property. Since this property does not exist, a null value is projected in its place.

MATCH (actor:Person {name: 'Bradley Cooper'})
RETURN actor {.*, .dateOfBirth} as bradley
┌─────────────────────────────────────────────────────────────┐
│ bradley                                                     │
├─────────────────────────────────────────────────────────────┤
│ {Map} 3 properties                                          │
│ {                                                           │
│   "dateOfBirth": null,                                      │
│   "name": "Bradley Cooper",                                 │
│   "oscars": 0                                               │
│ }                                                           │
└─────────────────────────────────────────────────────────────┘

Temporal types

The following temporal types are available: Duration, Date, LocalTime, LocalDateTime and ZonedDateTime.

Duration

You can create a property of temporal type Duration from a string or a map by calling the function duration().

Strings

For strings, the duration format is: P[nD]T[nH][nM][nS].

The n stands for a number, and the capital letters are used as a separator with each field in [] marked optional.

namedescription
DDays
HHours
MMinutes
SSeconds

When using strings, only the last filed can be a double, e.g., P2DT2.5H.

Example:

CREATE (:F1Laps {lap: duration("PT2M2.33S")});

Maps

Maps can contain the following six fields: day, hour, minute, second, millisecond and microsecond. Every field can be a double, an int or a mixture of both. Memgraph also supports negative durations.

Example:

CREATE (:F1Laps {lap: duration({minute:2, second:2, microsecond:33})});

Durations internally hold microseconds. Each of the fields specified above is first converted to microseconds and then reduced by addition to a single value. This has an interesting use case:

CREATE (:F1Laps {lap: duration({minute:2, second:-2, microsecond:-33})});

The query above converts minutes and seconds to microseconds and effectively produces the following equation: minutes - seconds - microseconds.

Each of the individual fields of a duration can be accessed through its properties as follows:

namedescription
dayConverts all the microseconds back to days and returns the value.
hourSubtracts days and returns the leftover value as hours.
minuteSubtracts the days and returns the leftover value as minutes.
secondSubtracts the days and returns the leftover value as seconds.
millisecondSubtracts the days and returns the leftover value as milliseconds.
microsecondSubtracts the days and returns the leftover value as microseconds.
nanosecondSubtracts the days and returns the leftover value as nanoseconds.

Examples:

CREATE (:F1Laps {lap: duration({day:1, hour: 2, minute:3, second:4})});
MATCH (f:F1Laps) RETURN f.lap.day;
// Result
>> 1
MATCH (f:F1Laps) RETURN f.lap.hour;
// Result
>> 2
MATCH (f:F1Laps) RETURN f.lap.minute;
// Result
>> 123 // The value without days is 2 hours and 3  minutes, that is 123 minutes
MATCH (f:F1Laps) RETURN f.lap.second;
// Result
>> 7384 // The value without days is 2 hours, 3 minutes and 4 seconds, that is 7384 seconds

Date

You can create a property of temporal type Date from a string or map by calling the function Date().

String

For strings, the date format is specified by the ISO 8601: YYYY-MM-DD or YYYYMMDD or YYYY-MM.

namedescription
YYear
MMonth
DDay

The lowest year is 0 and the highest is 9999.

Example:

CREATE (:Person {birthday: date("1947-07-30")});

You can also call date without arguments. This effectively sets the date field to the current date of the calendar (UTC clock).

Maps

For maps, three fields are available: year, month, day.

Example:

CREATE (:Person {birthday: date({year:1947, month:7, day:30})});

You can access the individual fields of a date through its properties:

namedescription
yearReturns the year field
monthReturns the month field
dayReturns the day field

Example:

MATCH (b:Person) RETURN b.birthday.year;

LocalTime

You can create a property of temporal type LocalTime from a string or map by calling the function localTime().

Strings

For strings, the local time format is specified by the ISO 8601: [T]hh:mm:ss or [T]hh:mm or [T]hhmmss or [T]hhmm or [T]hh.

namedescription
hHours
mMinutes
sSeconds

Example:

CREATE (:School {Calculus: localTime("09:15:00")});

seconds can be defined as decimal fractions with up to 6 digits. The first 3 digits represent milliseconds, and the last 3 digits microseconds. For example, the string T22:10:32.300600 specifies 300 milliseconds and 600 microseconds.

You can call localTime without arguments. This effectively sets the time field to the current time of the calendar (UTC clock).

Maps

For maps, five fields are available: hour, minute, second, millisecond and microsecond.

Example:

CREATE (:School {Calculus: localTime({hour:9, minute:15})});

You can access the individual fields of a LocalTime through its properties:

namedescription
hourReturns the hour field
minuteReturns the minute field
secondReturns the second field
millisecondReturns the millisecond field
microsecondReturns the microsecond field

Example:

MATCH (s:School) RETURN s.Calculus.hour;

LocalDateTime

You can create a property of temporal type LocalDateTime from a string or map by calling the function localDateTime(). LocalDateTime uses the defined timezone to convert between local and UTC time.

At a lower level, LocalDateTime will use system time (UTC), changing the instance timezone will change the displayed time point, but will not change the underlying data. All LocalDateTime is converted to UTC, so comparing time points between different timezones gives the correct result.

⚠️

When recovering from pre-2.19 snapshots and WALs, the observed LocalDateTime might change due to the introduction of the timezone.

Previously LocalDateTime was interpreted and saved as UTC time. Post 2.19, the displayed LocalDateTime is in the local timezone and gets converted to UTC time.

Pre 2.19 executing LocalDateTime() would return the current UTC time. Any such saved data is still "correct" post 2.19; timezone will correctly be applied and local time will be displayed.

Executing LocalDateTime("2024-07-24T13:30:00") will give different result pre and post 2.19. Pre 2.19 the string is parsed and assumed to be UTC time. Post 2.19 the time point is assumed to be in the set database timezone. This means that the two give different epoch offsets and are fundamentally different time points.

Strings

For strings, the local time format is specified by the ISO 8601: YYYY-MM-DDThh:mm:ss or YYYY-MM-DDThh:mm or YYYYMMDDThhmmss or YYYYMMDDThhmm or YYYYMMDDThh.

namedescription
YYear
MMonth
DDay
hHours
mMinutes
sSeconds

Example:

CREATE (:Flights {AIR123: localDateTime("2021-10-05T14:15:00")});

You can call localDateTime without arguments. This effectively sets the date and time fields to the current date and time of the calendar.

Maps

For maps the following fields are available: year, month, day, hour, minute, second, millisecond and microsecond.

Example:

CREATE (:Flights {AIR123: localDateTime({year:2021, month:10, day:5, hour:14, minute:15})});

You can access the individual fields of LocalDateTime through its properties:

namedescription
yearReturns the year field
monthReturns the month field
dayReturns the day field
hourReturns the hour field
minuteReturns the minute field
secondReturns the second field
millisecondReturns the millisecond field
microsecondReturns the microsecond field

Example:

MATCH (f:Flights) RETURN f.AIR123.year;

Database timezone

LocalDateTime uses the set database timezone to properly convert between system time (UTC) and local (user) time.

The timezone can be defined via:

  1. --timezone command-line argument
  2. SET DATABASE SETTING "timezone" TO "Europe/Rome" query

Both methods use IANA timezone descriptors to specify the timezone. See list of time zones (opens in a new tab).

ZonedDateTime

You can create a value of the ZonedDateTime type from a string or a map by calling the datetime() function.

Strings

The datetime() function takes strings that follow the ISO 8601 standard. An ISO 8601-compliant string that stands for a zoned datetime value has two parts: <DateTime><timezone>. The first part is defined the same way as LocalDateTime, and the second part follows one of the given timezone formats:

Examples:

CREATE (:Flight {AIR123: datetime("2024-04-21T14:15:00-07:00[America/Los_Angeles]")});
CREATE (:Flight {AIR123: datetime("2021-04-21T14:15:00Z")});

Maps

Maps for constructing ZonedDateTime values may have the following fields: year, month, day, hour, minute, second, millisecond, microsecond and timezone.

There are two options for the timezone field:

CREATE (:Flight {AIR123: datetime({year: 2024, month: 4, day: 21, hour: 14, minute: 15, timezone: "America/Los_Angeles"})});
CREATE (:Flight {AIR123: datetime({year: 2021, month: 4, day: 21, hour: 14, minute: 15, timezone: -60})});

No arguments

Calling datetime without passing arguments creates a ZonedDateTime value that reflects the current date and time in UTC.

Example:

CREATE (:Flight {AIR123: datetime()});

You can access the individual fields of ZonedDateTime through its properties:

namedescription
yearReturns the year field
monthReturns the month field
dayReturns the day field
hourReturns the hour field
minuteReturns the minute field
secondReturns the second field
millisecondReturns the millisecond field
microsecondReturns the microsecond field
timezoneReturns the timezone (as string)

Example:

MATCH (f: Flight) RETURN f.AIR123.timezone;

Temporal type arithmetic

The Duration, Date, LocalTime, LocalDateTime and ZonedDateTime types support native arithmetic, and the operations are summarized in the following tables:

Duration operations:

opresult
Duration + DurationDuration
Duration - DurationDuration
- DurationDuration

Date operations:

opresult
Date + DurationDate
Duration + DateDate
Date - DurationDate
Date - DateDuration

LocalTime operations:

opresult
LocalTime + DurationLocalTime
Duration + LocalTimeLocalTime
LocalTime - DurationLocalTime
LocalTime - LocalTimeDuration

LocalDateTime operations:

operationresult
LocalDateTime + DurationLocalDateTime
Duration + LocalDateTimeLocalDateTime
LocalDateTime - DurationLocalDateTime
LocalDateTime - LocalDateTimeDuration

ZonedDateTime operations:

operationresult
ZonedDateTime + DurationZonedDateTime
Duration + ZonedDateTimeZonedDateTime
ZonedDateTime - DurationZonedDateTime
ZonedDateTime - ZonedDateTimeDuration

Enum

Unlike other datatypes, enums requires that they are defined first. Each named enum had a set of values it can represent.

To create an enum:

CREATE ENUM Status VALUES { Good, Okay, Bad };

To see what enums exist use:

SHOW ENUMS;
┌─────────────────────────┬─────────────────────────┐
│ Enum Name               │ Enum Values             │
├─────────────────────────┼─────────────────────────┤
│ "Status"                │ ["Good", "Okay", "Bad"] │
└─────────────────────────┴─────────────────────────┘

To modify an existing enum by adding a new value use ALTER:

ALTER ENUM Status ADD VALUE Excellent;

To update an existing value in an enum do the following:

ALTER ENUM Status UPDATE VALUE Bad TO Poor;

Literals

Inside a query you can refer to enum values in their literal form name::value:

Examples:

CREATE (:Machine {status: Status::Good});
CREATE (:Machine {status: Status::Okay});
MATCH (n:Machine) WHERE n.status = Status::Bad RETURN n;

Strings

The ToEnum() function takes string(s) to lookup and return enum value.

Examples:

RETURN ToEnum("Status", "Good");
RETURN ToEnum("Status::Okay");

The Bolt protocol cannot directly handle enums. Therefore, enums are converted into a map before being sent to the client. Clients that have been updated to recognize this conversion will convert the map back into a readable enum format and display it nicely in the client-side results.

Point

Point is a spatial data type consisting of 2D or 3D locations in the Cartesian or WGS84 system. The coordinates of the location are stored as a 64-bit Float numbers. Each point type has an associated coordinate reference system (CRS) and a spatial reference identifier (SRID). Points can be created with the point function. For fast queries, points can leverage the point index.

Coordinate Reference Systems (CRS)

Memgraph supports four Coordinate Reference Systems (CRS) for spatial data, divided into two categories:

  1. WGS-84 CRS models points on the Earth’s surface using longitude and latitude based on the WGS84 (opens in a new tab) system.
  2. Cartesian CRS models points in Euclidean space using standard Cartesian coordinates.

CRS compatibility - Points in different CRSs cannot be directly compared or converted into one another, even if they share the same type (e.g., both WGS-84 or Cartesian). For example, a 2D point cannot be used in a 3D range query.

WGS-84

A WGS-84 point consists of longitude, latitude, and height if the point is 3D. Longitude and latitude are specified in degrees while height is specified in meters. Longitude has to be in the [-180, 180] range, latitude in the [-90, 90] range and height can be any Float value.

Point typeSRIDCRS
WGS-84 2D4326wgs-84
WGS-84 3D4979wgs-84-3d

Cartesian

Two types of Cartesian Coordinate Reference Systems (CRS) are supported, defining points in a flat, Euclidean space. Cartesian points can be either 2D or 3D. They consist of coordinates x, y, and z if the point is 3D. All coordinates can be any Float value.

Point typeSRIDCRS
Cartesian 2D7203cartesian
Cartesian 3D9157cartesian-3d

Point functions

point(parameters: map) -> [null, point]

Point function is used to create the point data type. It takes in a map of parameters to create the type. The point type can be specified using its crs or srid. If any of the parameters evaluates to null the point function returns null. Here are the examples of how to create a point, depending on thecrs and srd:

  • WGS-84 2D - A 2D geographic point in the WGS-84 CRS can be created in one of two ways:

    • longitude and latitude (if these are specified, and the crs is not, then the crs is assumed to be WGS-84).
    RETURN point({longitude:-73.93, latitude:40.73}) AS new_york;
    • x and y (in this case, the crs or srid must be specified or will be assumed to be Cartesian).
    RETURN point({x:-73.93, y:40.73, crs:'wgs-84'}) AS new_york;
  • WGS 84 3D - A 3D geographic point in the WGS-84 CRS can be created in one of two ways:

    • longitude, latitude, and either height or z (if these are specified, and the crs is not, then the crs is assumed to be WGS-84-3D).
    RETURN point({longitude:-73.93, latitude:40.73, height:10}) AS new_york;
    RETURN point({longitude:-73.93, latitude:40.73, z:10}) AS new_york;
    • x, y, and z (in this case, the crs or srid must be specified, or will be assumed to be Cartesian-3D).
    RETURN point({x:-73.93, y:40.73, z:10, srid:4979}) AS new_york;
  • Cartesian 2D - A 2D Cartesian point can be created by providing:

    • x and y (when provided, the point is assumed to reside in a two-dimensional Cartesian system).
    RETURN point({x:0, y:1}) AS cartesian_point;
  • Cartesian 3D - A 3D Cartesian point can be created by providing:

    • x, y, and z (when provided, the point is assumed to reside in a three-dimensional Cartesian system).
    RETURN point({x:0, y:1, z:2}) AS cartesian_point;

point.distance(x: [null, point], y: [null, point]) -> [null, float]

The point.distance function returns the distance between two points. Distance can only be calculated between points of the same type. For WGS-84 points the distance is calculated in meters and is calculated using the Haversine (opens in a new tab) formula. For WGS-84 3D points the Haversine formula is applied to longitude and latitude and then the Pythagorean theorem is applied between the calculated distance and the height. For Cartesian points, the Pythagorean theorem is applied. If any of the arguments of the point.distance function evaluates to null or the point types don't match then the function returns null.

Usage:

Example of the distance between two points in WGS-84 2D:

  WITH point({longitude: 51.51, latitude: -0.12}) as london,
       point({longitude: 45.82, latitude: 15.97}) as zagreb
  RETURN point.distance(london, zagreb) AS result;
+----------------------------+
| result                     |
+----------------------------+
| 1.88621e+06                |
+----------------------------+

Example of the distance between two points in 2D Cartesian space:

  RETURN point.distance(
              point({x: 0, y: 0}),
              point({x: 3, y: 3})
            ) AS result;
+----------------------------+
| result                     |
+----------------------------+
| 4.24264                    |
+----------------------------+

point.withinbbox(point: [null, point], lower_left_corner: [null, point], upper_right_corner: [null, point]) -> [null, boolean]

The point.withinbbox function returns whether the given point is inside or on the edge of the bounding box created by lower_left_corner and upper_right_corner. For WGS-84 points this also works if crossing the the international date line.

Usage:

Example of a point inside the bounding box:

  RETURN point.withinbbox(
              point({x:   0, y:  0}),
              point({x:  -1, y: -1}),
              point({x:   1, y:  1})
            ) AS result;
+----------------------------+
| result                     |
+----------------------------+
| true                       |
+----------------------------+

Example of crossing the international date line:

  RETURN point.withinbbox(
              point({longitude:  180, latitude: 58.0}),
              point({longitude:  179, latitude: 57.0}),
              point({longitude: -179, latitude: 59.0})
            ) AS result;
+----------------------------+
| result                     |
+----------------------------+
| true                       |
+----------------------------+

If any of the arguments of the point.withinbbox function evaluates to null or the point types don't match then the function returns null.

Procedures API

Data types are also used within query modules. Check out the documentation for the Python API, C API and C++ API.