# 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.

There are **no restrictions on the number of propertie**s that can be stored in
a single graph element. The only restriction is that the values must be of the
supported types. There is **no hard limit** on the size or complexity of data
values either - the only practical limit is the **amount of available RAM
memory** on your machine.

Below is a table of supported data types:

| Type                              | Description                                                                                         |
| --------------------------------- | --------------------------------------------------------------------------------------------------- |
| `Null`                            | Property has no value, which is the same as if the property doesn't exist.                          |
| `String`                          | A character string (text).                                                                          |
| `Boolean`                         | A boolean value, either `true` or `false`.                                                          |
| `Integer`                         | An integer number.                                                                                  |
| `Float`                           | A floating-point number (real number).                                                              |
| `List`                            | A list containing any number of property values of any supported type under a single property name. |
| [`Map`](#maps)                    | A mapping of string keys to values of any supported type.                                           |
| [`Duration`](#duration)           | A period of time.                                                                                   |
| [`Date`](#date)                   | A date with year, month, and day.                                                                   |
| [`LocalTime`](#localtime)         | Time without the timezone.                                                                          |
| [`LocalDateTime`](#localdatetime) | Date and time without the timezone.                                                                 |
| [`ZonedDateTime`](#zoneddatetime) | Date and time in a specific timezone.                                                               |
| [`Enum`](#enum)                   | An enumeration value.                                                                               |
| [`Point`](#point)                 | 2D or 3D point either in Cartesian or WGS format.                                                   |

> **Info**
>
> If you want to modify `List` and `Map` property values, you need to replace them
> entirely.
>
> The following queries are valid:
>
> ```cypher
CREATE (:Node {property: [1, 2, 3]});
CREATE (:Node {property: {key: "value"}});
```
>
> But these are not:
>
> ```cypher
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:

```cypher
RETURN {key: 'Value', listKey: [{inner: 'Map1'}, {inner: 'Map2'}]}
```

```copy=false
┌─────────────────────────────────────────────────────────────┐
│ {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 `}`.

```cypher
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:

**Graph**

![](https://memgraph.com/docs/pages/fundamentals/data-types/map-projection-example.png)

**Load queries**

```cypher
MATCH (n) DETACH DELETE n;
CREATE
(bradley:Person {name: 'Bradley Cooper', oscars: 0}),
(jennifer:Person {name: 'Jennifer Lawrence', oscars: 1}),
(slp:Movie {title: 'Silver Linings Playbook', released: 2012}),
(amhu:Movie {title: 'American Hustle', released: 2013}),
(joy:Movie {title: 'Joy', released: 2015}),
(asib:Movie {title: 'A Star Is Born', released: 2018}),
(dlu:Movie {title: 'Don’t Look Up', released: 2021}),
(bradley)-[:ACTED_IN]->(slp),
(bradley)-[:ACTED_IN]->(amhu),
(bradley)-[:ACTED_IN]->(joy),
(bradley)-[:ACTED_IN]->(asib),
(jennifer)-[:ACTED_IN]->(slp),
(jennifer)-[:ACTED_IN]->(amhu),
(jennifer)-[:ACTED_IN]->(joy),
(jennifer)-[:ACTED_IN]->(dlu);
```

**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()`.

```cypher
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
```

```plaintext copy=false
┌─────────────────────────────────────────────────────────────┐
│ 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.

```cypher
MATCH (actor:Person)-[:ACTED_IN]->(movie:Movie)
WITH actor, count(movie) AS nMovies
RETURN actor {.name, nMovies}
```

```plaintext copy=false
┌─────────────────────────────────────────────────────────────┐
│ 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.

```cypher
MATCH (actor:Person {name: 'Bradley Cooper'})
RETURN actor {.*, .dateOfBirth} as bradley
```

```plaintext copy=false
┌─────────────────────────────────────────────────────────────┐
│ 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()`. The function also accepts `null` as an argument, in which case it returns `null`.

**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.

| name | description |
| :--: | :---------: |
|  D   |    Days     |
|  H   |    Hours    |
|  M   |   Minutes   |
|  S   |   Seconds   |

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

Example:

```cypher
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:

```cypher
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:

```cypher
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:

|    name     |                            description                             |
| :---------: | :----------------------------------------------------------------: |
|     day     | Converts all the microseconds back to days and returns the value.  |
|    hour     |      Subtracts days and returns the leftover value as hours.       |
|   minute    |   Subtracts the days and returns the leftover value as minutes.    |
|   second    |   Subtracts the days and returns the leftover value as seconds.    |
| millisecond | Subtracts the days and returns the leftover value as milliseconds. |
| microsecond | Subtracts the days and returns the leftover value as microseconds. |
| nanosecond  | Subtracts the days and returns the leftover value as nanoseconds.  |

Examples:

```cypher
CREATE (:F1Laps {lap: duration({day:1, hour: 2, minute:3, second:4})});
```

```cypher
MATCH (f:F1Laps) RETURN f.lap.day;
// Result
>> 1
```

```cypher
MATCH (f:F1Laps) RETURN f.lap.hour;
// Result
>> 2
```

```cypher
MATCH (f:F1Laps) RETURN f.lap.minute;
// Result
>> 123 // The value without days is 2 hours and 3  minutes, that is 123 minutes
```

```cypher
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()`. The function also accepts `null` as an argument, in which case it returns `null`.

**String**

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

| name | description |
| :--: | :---------: |
|  Y   |    Year     |
|  M   |    Month    |
|  D   |     Day     |

The lowest year is `0` and the highest is `9999`.

Example:

```cypher
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:

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

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

| name  |       description       |
| :---: | :---------------------: |
| year  | Returns the year field  |
| month | Returns the month field |
|  day  |  Returns the day field  |

Example:

```cypher
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()`. The function also accepts `null` as an argument, in which case it returns `null`.

**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`.

| name | description |
| :--: | :---------: |
|  h   |    Hours    |
|  m   |   Minutes   |
|  s   |   Seconds   |

Example:

```cypher
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:

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

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

|    name     |          description          |
| :---------: | :---------------------------: |
|    hour     |    Returns the hour field     |
|   minute    |   Returns the minute field    |
|   second    |   Returns the second field    |
| millisecond | Returns the millisecond field |
| microsecond | Returns the microsecond field |

Example:

```cypher
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()`. The function also accepts `null` as an argument, in which case it returns `null`.
LocalDateTime uses the defined [timezone](#database-timezone) to convert between local and UTC time.

> **Info**
>
> 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.

> **Warning**
>
> 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`.

| name | description |
| :--: | :---------: |
|  Y   |    Year     |
|  M   |    Month    |
|  D   |     Day     |
|  h   |    Hours    |
|  m   |   Minutes   |
|  s   |   Seconds   |

Example:

```cypher
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:

```cypher
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:

|    name     |          description          |
| :---------: | :---------------------------: |
|    year     |    Returns the year field     |
|    month    |    Returns the month field    |
|     day     |     Returns the day field     |
|    hour     |    Returns the hour field     |
|   minute    |   Returns the minute field    |
|   second    |   Returns the second field    |
| millisecond | Returns the millisecond field |
| microsecond | Returns the microsecond field |

Example:

```cypher
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
1. `SET DATABASE SETTING "timezone" TO "Europe/Rome"` query

Both methods use IANA timezone descriptors to specify the timezone. See [list of time zones](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List).

> **Warning**
>
> Starting with `tzdata` version `2024b`, its format has changed and an incompatibility with the current libstdc++ has been introduced.
> As a result, using `tzdata` version `2024b` or later will break the timezone feature in Memgraph. This could lead to incorrect handling of timezones and unexpected behavior in your application.
> To avoid compatibility issues, please ensure that you are using `tzdata` `v2024a` or earlier with Memgraph until libstdc++ has been updated to support the new format in tzdata.

### ZonedDateTime

You can create a value of the `ZonedDateTime` type from a string or a map by
calling the `datetime()` function. The function also accepts `null` as an argument, in which case it returns `null`.

**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](#localdatetime), and the second part follows one of the given
timezone formats:
* `Z`
* `±hh:mm`
* `±hh:mm[ZoneName]`
* `±hhmm`
* `±hhmm[ZoneName]`
* `±hh`
* `±hh[ZoneName]`
* `[ZoneName]`,
where `ZoneName` is a timezone name from the
[IANA timezone database](https://en.wikipedia.org/wiki/Tz_database).

Examples:

```cypher
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`. 
- If some numeric fields are omitted, they default to the lowest value for that field:
     - `0` for `year`, `hour`, `minute`, `second`, `millisecond`, and `microsecond`.
     - `1` for `month` and `day`. 
- If the `timezone` is omitted, it defaults to UTC. 
- If all numeric fields are omitted and only the `timezone` is specified, then a `datetime`
represents the **current time** in the that timezone.

There are two options for the `timezone` field:
* string: timezone name from the
[IANA timezone database](https://en.wikipedia.org/wiki/Tz_database)
* int: offset from UTC (in minutes)

```cypher
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:

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

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

|    name     |          description             |
| :---------: | :------------------------------: |
| year        | Returns the year field           |
| month       | Returns the month field          |
| day         | Returns the day field            |
| hour        | Returns the hour field           |
| minute      | Returns the minute field         |
| second      | Returns the second field         |
| millisecond | Returns the millisecond field    |
| microsecond | Returns the microsecond field    |
| timezone    | Returns the timezone (as string) |

Example:

```cypher
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:

|         op          |  result  |
| :-----------------: | :------: |
| Duration + Duration | Duration |
| Duration - Duration | Duration |
|     - Duration      | Duration |

Date operations:

|       op        |  result  |
| :-------------: | :------: |
| Date + Duration |   Date   |
| Duration + Date |   Date   |
| Date - Duration |   Date   |
|   Date - Date   | Duration |

LocalTime operations:

|          op           |  result   |
| :-------------------: | :-------: |
| LocalTime + Duration  | LocalTime |
| Duration + LocalTime  | LocalTime |
| LocalTime - Duration  | LocalTime |
| LocalTime - LocalTime | Duration  |

LocalDateTime operations:

|           operation           |    result     |
| :---------------------------: | :-----------: |
|   LocalDateTime + Duration    | LocalDateTime |
|   Duration + LocalDateTime    | LocalDateTime |
|   LocalDateTime - Duration    | LocalDateTime |
| LocalDateTime - LocalDateTime |   Duration    |

ZonedDateTime operations:

|           operation           |    result     |
| :---------------------------: | :-----------: |
| ZonedDateTime + Duration      | ZonedDateTime |
| Duration + ZonedDateTime      | ZonedDateTime |
| ZonedDateTime - Duration      | ZonedDateTime |
| ZonedDateTime - ZonedDateTime | Duration      |

## Enum

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

> **Info**
>
> To create an enum:
>
> ```cypher
CREATE ENUM Status VALUES { Good, Okay, Bad };
```
>
> To see what enums exist use:
>
> ```cypher
SHOW ENUMS;
```
>
> ```plaintext copy=false
┌─────────────────────────┬─────────────────────────┐
│ Enum Name               │ Enum Values             │
├─────────────────────────┼─────────────────────────┤
│ "Status"                │ ["Good", "Okay", "Bad"] │
└─────────────────────────┴─────────────────────────┘
```
>
> To modify an existing enum by adding a new value use [ALTER](https://memgraph.com/docs/querying/clauses/alter):
>
> ```cypher
ALTER ENUM Status ADD VALUE Excellent;
```
>
> To update an existing value in an enum do the following:
>
> ```cypher
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:

```cypher
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:

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

> **Info**
>
> 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](#point-functions). For fast queries, points can
leverage the [point index](https://memgraph.com/docs/fundamentals/indexes#point-index).

Converting a point to a string (for example with
[`toString`](https://memgraph.com/docs/querying/functions)) yields its Cypher form,
`POINT({ x:1, y:2, srid: 7203 })` for 2D points and
`POINT({ x:1, y:2, z:3, srid: 9157 })` for 3D points.

### Coordinate Reference Systems

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](https://epsg.io/4326) system.
2. **Cartesian CRS** models points in Euclidean space using standard Cartesian
   coordinates.

> **Info**
>
> **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 type      |  SRID        |    CRS     |
| :---------------:  | :----------: | :--------: |
|     WGS-84 2D      | 4326         |  wgs-84    |
|     WGS-84 3D      | 4979         |  wgs-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 type      |  SRID        |    CRS        |
| :---------------:  | :----------: | :-----------: |
|     Cartesian 2D   | 7203         |  cartesian    |
|     Cartesian 3D   | 9157         |  cartesian-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 the`crs` 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`).
```cypher
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).
```cypher
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`).
```cypher
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).
```cypher
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).
```cypher
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).
```cypher
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](https://en.wikipedia.org/wiki/Haversine_formula) 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:
```cypher
  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;
```
```plaintext
+----------------------------+
| result                     |
+----------------------------+
| 1.88621e+06                |
+----------------------------+
```

Example of the distance between two points in 2D Cartesian space:
```cypher
  RETURN point.distance(
              point({x: 0, y: 0}),
              point({x: 3, y: 3})
            ) AS result;
```
```plaintext
+----------------------------+
| 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:
```cypher
  RETURN point.withinbbox(
              point({x:   0, y:  0}),
              point({x:  -1, y: -1}),
              point({x:   1, y:  1})
            ) AS result;
```
```plaintext
+----------------------------+
| result                     |
+----------------------------+
| true                       |
+----------------------------+
```

Example of crossing the international date line:
```cypher
  RETURN point.withinbbox(
              point({longitude:  180, latitude: 58.0}),
              point({longitude:  179, latitude: 57.0}),
              point({longitude: -179, latitude: 59.0})
            ) AS result;
```
```plaintext
+----------------------------+
| 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](https://memgraph.com/docs/custom-query-modules/python/python-api), [C
API](https://memgraph.com/docs/custom-query-modules/c/c-api) and [C++
API](https://memgraph.com/docs/custom-query-modules/cpp/cpp-api).
