Skip to content

Language Primitives

/

Data types

Values

Each of the types mentioned in the data model is a subset of an all-encompassing type called a value.

While it is unsurprising that a data type can be compared with itself, it may be surprising that different types can also be compared with each other.

9 > 1;            // Returns true
[] > time::now(); // Also returns true

This comparison is possible because every type in SurrealDB is a subset of value, and a comparison of any type with another is also simply a comparison of a value with another value. The order of values from least to greatest is:

  • none

  • null

  • bool

  • number

  • string

  • duration

  • datetime

  • uuid

  • array

  • set

  • object

  • geometry

  • bytes

  • table

  • record

  • file

  • regex

  • range

Numbers of every type, including sized numbers such as 5u8, are ordered together by their value.

As a result, all of the following return true.

[
    null > none,
    true > null,
    1 > true,
    'a' > 999999999,
    1m > 'a',
    time::now() > 1m,
    rand::uuid() > time::now(),
    [ 9, 10 ] > rand::uuid(),
    { 9, 10 } > [ 9, 10 ],
    {} > { 9, 10 },
    (9.9, 9.9) > {},
    <bytes>"Aeon" > (9.9, 9.9),
    type::table("person") > <bytes>"Aeon",
    person:one > type::table("person"),
    f"file://myfile.txt" > person:one,
    <regex>"a|b" > f"file://myfile.txt",
    0..10 > <regex>"a|b",
    (|| 1) > 0..10
];

Being able to compare a value with any other value is what makes SurrealDB's record range syntax possible.

CREATE time_data:[d'2024-07-23T00:00:00.000Z'];
CREATE time_data:[d'2024-07-24T00:00:00.000Z'];
CREATE time_data:[d'2024-07-25T00:00:00.000Z'];
-- Records from the 24th to the 25th
SELECT * FROM time_data:[d'2024-07-24']..[d'2024-07-25'];
-- Records from the 24th
SELECT * FROM time_data:[d'2024-07-24']..;
-- All records
SELECT * FROM time_data:[NONE]..;

The .. open-range syntax also represents an infinite value inside a record range query, making it the greatest possible value and the inverse of NONE, the lowest possible value. A part of a record range query that begins with NONE and ends with .. will thus filter out nothing.

CREATE temperature:['London', d'2025-02-19T00:00:00.000Z'] SET val = 5.5;
CREATE temperature:['London', d'2025-02-20T00:00:00.000Z'] SET val = 5.7;

-- Return all records as long as index 0 = 'London'
SELECT * FROM temperature:['London', NONE]..=['London', ..];
Output
[
	{
		id: temperature:[
			'London',
			d'2025-02-19T00:00:00Z'
		],
		val: 5.5f
	},
	{
		id: temperature:[
			'London',
			d'2025-02-20T00:00:00Z'
		],
		val: 5.7f
	}
]

Inside a schema, the keyword any is used to denote any possible value.

DEFINE FIELD anything ON TABLE person TYPE any;

Any value is considered to be truthy if it is not NONE, NULL, or a default value for the data type. A data type at its default value is one that is empty, such as an empty string or array or object, or a number set to 0.

The following example shows the result of the array::all() method, which checks to see if all of the items inside an array are truthy or not.

array::all(["", 1, 2, 3]); // false because of ""
array::all([{}, 1, 2, 3]); // false because of {}
array::all(["SurrealDB", { is_nice_database: true }, 1, 2, 3]);  // true

As the ! operator reverses the truthiness of a value, a doubling of this operator can also be used to check for truthiness.

[
    !!"Has a value", !!"",             // true, false
    !!true, !!false,                   // true, false
    !!{ is_nice_database: true }, !!{} // true, false
    ];

Available since: v3.3.0

A value can be nested at most 256 levels deep. Each array, set, object and range adds a level, and so does the key of a record ID, so a compound ID such as t:[[1]] counts towards the same limit. The limit is fixed and cannot be configured.

A write that would store a deeper value fails with The value is nested too deeply, whether the value arrives in one statement or grows one level at a time through repeated updates. A deeper value that is already stored returns the same error when it is read. The parsing depth limits are separate: they bound how deeply a query or a message may nest, while this limit applies to the value itself.

CREATE deep:1 SET v = 1;
-- Wrap the value in one more array on each pass
FOR $i IN 1..300 {
	UPDATE deep:1 SET v = [v];
};
Output of the FOR loop
'The value is nested too deeply. A value may be nested at most 256 levels; reduce the nesting or split the data across records'

From SurrealDB 3.3.4, the limit also applies to a value that is built in memory and never stored. A query that builds such a value fails with the same error instead of stopping the server. This covers:

  • the accumulator of array::fold(), array::reduce(), set::fold() and set::reduce()

  • a parameter set with LET, DEFINE PARAM or ALTER PARAM

  • the arguments of DEFINE API middleware

  • the paths of a JSON patch

  • a value returned from an embedded JavaScript function

  • every query result

array::fold(array::range(0, 300), [], |$acc, $_| [$acc]);
Error output
'The value is nested too deeply. A value may be nested at most 256 levels; reduce the nesting or split the data across records'

From 3.3.4, the levels of a GeometryCollection also count towards the limit.

Warning

A record stored by a release before 3.3.4 can hold a GeometryCollection that goes past 256 levels once its own levels are counted. After upgrading to 3.3.4 or later, including 4.0, reading that record returns The value is nested too deeply, and so does any statement that reads it, including a SELECT over its table. To repair the record, overwrite the field with a value that is not as deep, for example UPDATE deep:1 SET g = NONE;. The record does not need to be deleted.

Was this page helpful?