AGE uses a custom data type named agtype, which is the only data type returned by AGE. agtype is a superset of JSON and a custom implementation of PostgreSQL’s jsonb.
In Cypher, null represents a missing or undefined value. Conceptually, null means “a missing unknown value” and behaves differently from all other values. For example, accessing a non-existent property on a vertex yields null. Most expressions that take null as input return null, including Boolean predicates in WHERE clauses. In such cases, any value that is not true is treated as false. null is not equal to null: not knowing whether two values are equal does not imply they are equal. Therefore, the expression null = null evaluates to null, not true.
Query
SELECT *
FROM cypher('graph_name', $$
RETURN NULL
$$) AS (null_result agtype);
null displays as blank.
Result
null_result
(1 row)
The concept of NULL in agtype and in PostgreSQL is identical to that in Cypher.
The integer type stores whole numbers — numeric values without fractional components. It is a 64-bit signed field, supporting values from -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807. Attempts to store values outside this range raise an error.
integer offers the best balance among value range, storage size, and performance. smallint is used only when disk space is constrained. bigint is intended for cases where integer’s range is insufficient.
Query
SELECT *
FROM cypher('graph_name', $$
RETURN 1
$$) AS (int_result agtype);
Result
| int_result |
| ---------- |
| 1 |
(1 row)
The float data type is an imprecise, variable-precision numeric type conforming to the IEEE-754 standard.
“Imprecise” means some values cannot be represented exactly in the internal format and are instead stored as approximations. Slight discrepancies may therefore occur between stored and retrieved values. Managing such errors — and their propagation through arithmetic — is the subject of an entire discipline in mathematics and computer science. While beyond the scope of this document, the following points are critical:
numeric type for exact storage and computation (e.g., monetary amounts). Values that are too large or too small raise an error. Excessively precise inputs may be rounded. Values too close to zero to be represented distinctly from zero cause underflow errors.
In addition to ordinary numeric values, float supports several special values:
Infinity -Infinity NaNThese correspond to the IEEE 754 special values “positive infinity”, “negative infinity”, and “not-a-number”. To use these as literals in Cypher commands, they must be quoted and explicitly cast, for example:
SET x.float_value = '-Infinity'::float
Input strings for these values are matched case-insensitively.
To specify a float, include a decimal point.
Query
SELECT *
FROM cypher('graph_name', $$
RETURN 1.0
$$) AS (float_result agtype);
Result
| float_result |
| ------------ |
| 1.0 |
(1 row)
— Coming soon —
AGE provides the standard Cypher boolean type. The boolean type has three possible states: true, false, and a third state — unknown — represented by an agtype null value.
Boolean literals are written using the keywords TRUE, FALSE, and NULL in Cypher queries.
Query
SELECT *
FROM cypher('graph_name', $$
RETURN TRUE
$$) AS (boolean_result agtype);
Unlike PostgreSQL, AGE outputs full words (true, false) rather than single-character abbreviations (t, f).
Result
| boolean_result |
| -------------- |
| true |
(1 row)
agtype string literals support the following escape sequences:
| Escape Sequence | Character |
|---|---|
\t |
Tab |
\b |
Backspace |
\n |
Line feed (newline) |
\r |
Carriage return |
\f |
Form feed |
' |
Single quote |
" |
Double quote |
\\ |
Backslash |
\uXXXX |
Unicode UTF-16 code point (exactly four hexadecimal digits after \u) |
Strings are delimited by single quotes ('). Output uses double quotes (").
Query
SELECT *
FROM cypher('graph_name', $$
RETURN 'This is a string'
$$) AS (string_result agtype);
Result
| string_result |
| ------------------ |
| "This is a string" |
(1 row)
All examples use WITH and RETURN clauses.
Literal lists are created using square brackets with comma-separated elements.
Query
SELECT *
FROM cypher('graph_name', $$
WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] AS lst
RETURN lst
$$) AS (lst agtype);
Result
| lst |
| ---------------------------------- |
| [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] |
(1 row)
Lists may contain null values. Unlike standalone null, null inside a list appears as the literal word null.
Query
SELECT *
FROM cypher('graph_name', $$
WITH [null] AS lst
RETURN lst
$$) AS (lst agtype);
Result
| lst |
| ------- |
| [null] |
(1 row)
Use square brackets to access individual list elements. Syntax list[start..end] returns elements from index start (inclusive) to end (exclusive).
Query
SELECT *
FROM cypher('graph_name', $$
WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] AS lst
RETURN lst[3]
$$) AS (element agtype);
Result
| element |
| ------- |
| 3 |
(1 row)
Query
SELECT *
FROM cypher('graph_name', $$
WITH [0, {key: 'key_value'}, 2, 3, 4, 5, 6, 7, 8, 9, 10] AS lst
RETURN lst
$$) AS (map_value agtype);
Result
| map_value |
| ----------------------------------------------------- |
| [0, {"key": "key_value"}, 2, 3, 4, 5, 6, 7, 8, 9, 10] |
(1 row)
Query
SELECT *
FROM cypher('graph_name', $$
WITH [0, {key: 'key_value'}, 2, 3, 4, 5, 6, 7, 8, 9, 10] AS lst
RETURN lst[1].key
$$) AS (map_value agtype);
Result
| map_value |
| ----------- |
| "key_value" |
(1 row)
Negative indices count backward from the end of the list.
Query
SELECT *
FROM cypher('graph_name', $$
WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] AS lst
RETURN lst[-3]
$$) AS (element agtype);
Result
| element |
| ------- |
| 8 |
(1 row)
Square brackets support ranges to extract subsequences.
Query
SELECT *
FROM cypher('graph_name', $$
WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] AS lst
RETURN lst[0..3]
$$) AS (element agtype);
Result
| element |
| --------- |
| [0, 1, 2] |
(1 row)
Query
SELECT *
FROM cypher('graph_name', $$
WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] AS lst
RETURN lst[0..-5]
$$) AS (lst agtype);
Result
| lst |
| ------------------ |
| [0, 1, 2, 3, 4, 5] |
(1 row)
Omitting the start index defaults to 0.
Query
SELECT *
FROM cypher('graph_name', $$
WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] AS lst
RETURN lst[..4]
$$) AS (lst agtype);
Result
| lst |
| ------------ |
| [0, 1, 2, 3] |
(1 row)
Omitting the end index defaults to the list length.
Query
SELECT *
FROM cypher('graph_name', $$
WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] AS lst
RETURN lst[-5..]
$$) AS (lst agtype);
Result
| lst |
| ------------------ |
| [6, 7, 8, 9, 10] |
(1 row)
Out-of-bounds slices are truncated silently. Out-of-bounds single-element access returns null.
Query
SELECT *
FROM cypher('graph_name', $$
WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] AS lst
RETURN lst[15]
$$) AS (element agtype);
Result
| element |
| ------- |
| |
(1 row)
Query
SELECT *
FROM cypher('graph_name', $$
WITH [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] AS lst
RETURN lst[5..15]
$$) AS (element agtype);
Result
| element |
| ------------------- |
| [5, 6, 7, 8, 9, 10] |
(1 row)
Maps can be constructed directly in Cypher.
A simple map can be built using basic agtype values.
Query
SELECT *
FROM cypher('graph_name', $$
WITH {int_key: 1, float_key: 1.0, numeric_key: 1::numeric, bool_key: true, string_key: 'Value'} AS m
RETURN m
$$) AS (m agtype);
Result
| m |
| ---------------------------------------------------------------------------------------------------- |
| {"int_key": 1, "bool_key": true, "float_key": 1.0, "string_key": "Value", "numeric_key": 1::numeric} |
(1 row)
Maps may contain composite types — e.g., lists and nested maps.
Query
SELECT *
FROM cypher('graph_name', $$
WITH {listKey: [{inner: 'Map1'}, {inner: 'Map2'}], mapKey: {i: 0}} AS m
RETURN m
$$) AS (m agtype);
Result
| m |
| ----------------------------------------------------------------------- |
| {"mapKey": {"i": 0}, "listKey": [{"inner": "Map1"}, {"inner": "Map2"}]} |
(1 row)
Query
SELECT *
FROM cypher('graph_name', $$
WITH {int_key: 1, float_key: 1.0, numeric_key: 1::numeric, bool_key: true, string_key: 'Value'} AS m
RETURN m.int_key
$$) AS (int_key agtype);
Result
| int_key |
| ------- |
| 1 |
(1 row)
Query
SELECT *
FROM cypher('graph_name', $$
WITH {listKey: [{inner: 'Map1'}, {inner: 'Map2'}], mapKey: {i: 0}} AS m
RETURN m.listKey[0]
$$) AS (m agtype);
Result
| m |
| ----------------- |
| {"inner": "Map1"} |
(1 row)
Entities have unique, comparable identifiers used to determine equality.
Each entity is assigned a set of properties, each uniquely identified within the set by its property key.
Simple entities are assigned a unique graphid. A graphid is a unique combination of a label ID and a sequence number assigned per label. Note that graphids may overlap across different graphs.
A graphid is fundamentally a signed 64-bit integer (int64).
The 64 bits are partitioned as follows:
<--- 16 bits ---> |
<----------- 48 bits -----------> |
|---|---|
| Label ID | Entry ID |
| (bits 63–48) | (bits 47–0) |
1 to 65535 (PG_UINT16_MAX). 0 is invalid. 1 to 281474976710655 (0x0000ffffffffffff). 0 is invalid.Labels are identifiers that classify vertices and edges into specific categories.
For information on creating labeled entities, see the CREATE clause.
Note!
In YMatrix AGE, labels are implemented as database tables — i.e., one label maps to exactly one table.
Both vertices and edges may have properties. Properties are key-value pairs, where each property name must be a string.
vertex is a fundamental graph entity with independent existence and unique identity. Data Format
| Field Name | Description |
|---|---|
id |
The vertex’s graphid |
label |
The vertex’s label name |
properties |
Properties associated with the vertex |
{id:1; label: 'label_name'; properties: {prop1: value1, prop2: value2}}::vertex
Query
SELECT *
FROM cypher('graph_name', $$
WITH {id: 0, label: "label_name", properties: {i: 0}}::vertex AS v
RETURN v
$$) AS (v agtype);
Result
| v |
| ---------------------------------------------------------------- |
| {"id": 0, "label": "label_name", "properties": {"i": 0}}::vertex |
(1 row)
An edge is a directed connection between two nodes — a source node and a target node. An outgoing edge is viewed from the source node’s perspective; an incoming edge is viewed from the target node’s perspective. Each edge is assigned exactly one edge type.
Data Format
| Field Name | Description |
|---|---|
id |
The edge’s graphid |
startid |
The graphid of the source node |
endid |
The graphid of the target node |
label |
The edge’s label name |
properties |
Properties associated with the edge |
Output Format
{id: 3; startid: 1; endid: 2; label: 'edge_label'; properties: {prop1: value1, prop2: value2}}::edge
Query
SELECT *
FROM cypher('graph_name', $$
WITH {id: 2, start_id: 0, end_id: 1, label: "label_name", properties: {i: 0}}::edge AS e
RETURN e
$$) AS (e agtype);
Result
| e |
| ------------------------------------------------------------------------------------------ |
| {"id": 2, "label": "label_name", "end_id": 1, "start_id": 0, "properties": {"i": 0}}::edge |
(1 row)
A path is an alternating sequence of vertices and edges. A path must begin with a vertex and contain at least one edge.
Query
SELECT *
FROM cypher('graph_name', $$
WITH [{id: 0, label: "label_name_1", properties: {i: 0}}::vertex,
{id: 2, start_id: 0, end_id: 1, label: "edge_label", properties: {i: 0}}::edge,
{id: 1, label: "label_name_2", properties: {}}::vertex
]::path AS p
RETURN p
$$) AS (p agtype);
Result
| p |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [{"id": 0, "label": "label_name_1", "properties": {"i": 0}}::vertex, {"id": 2, "label": "edge_label", "end_id": 1, "start_id": 0, "properties": {"i": 0}}::edge, {"id": 1, "label": "label_name_2", "properties": {}}::vertex]::path |
(1 row)