• Start

Concepts & Guides

Working with types

Tips for working with data types in SurrealDB, including arrays, type safety, typed LET statements, and chaining array functions.

This page contains a number of examples and tips for working with various data types that go beyond the general API documentation for each type.

For general information on these data types, see the data types page in the query language documentation.

Working with arrays is one of the most important skills when working with SurrealDB, as SELECT statements return an array of values by default unless the ONLY keyword is used on an array that contains a single item.

-- Even this returns an array
SELECT * FROM 9;
-- Use the `ONLY` clause to return a single item
SELECT * FROM ONLY 9;
-- Error: array has more than one item
SELECT * FROM ONLY [1,9];

Output

-------- Query 1  --------

[
9
]

-------- Query 2 --------

9

-------- Query 3 --------

'Expected a single result output when using the ONLY keyword'

This also means that a SELECT statement used to fetch records from a datastore can be used unchanged for any other array of values.

LET $ten_items = [8,5,3,2,6,4,76,9,8,5];
SELECT * FROM $ten_items START 5 LIMIT 5;

Output

[
4,
76,
9,
8,
5
]

Other syntax can be used to achieve the same result, such as pulling from a range of indexes.

LET $ten_items = [8,5,3,2,6,4,76,9,8,5];
$ten_items[5..10];

Using typed LET statements is a good practice when prototyping code or when getting used to SurrealQL for the first time. Take the following example that attempts to count the number of true values in a field by filtering out values that are not true, without noticing that the field actually contains strings instead of booleans. The query output ends up being 0, rather than the expected 2.

CREATE some:record SET vals = ["true", "false", "true"];
some:record.vals.filter(|$val| $val = true).len();

Output

0

Breaking this into multiple typed LET statements shows the error right away.

LET $vals: array<bool> = some:record.vals;
LET $len: number = $vals.filter(|$val| $val = true).len();
$len;

Output

-------- Query 1 --------

"Tried to set `$vals`, but couldn't coerce value: Expected `bool`
but found `'true'` when coercing an element of `array<bool>`"

-------- Query 2 --------

'There was a problem running the filter() function.
no such method found for the none type'

-------- Query 3 --------

NONE

With the location of the error in clear sight, a fix is that much easier to implement.

LET $vals: array<bool> = some:record.vals.map(|$val| <bool>$val);
LET $len: number = $vals.filter(|$val| $val = true).len();
$len;

Output

2

The array::map() function provides access to each item in an array, allowing an operation to be performed on it before being passed on. Other similar functions can also be used, such as array::filter() which passes on an array that only contains the items that return true to an expression of your choice.

The following example shows how to chain these functions to validate and modify data in a single statement. The example below removes any items with a NONE, checks to see if the location data is a valid geometric point, and then returns the remaining items as objects with a different structure.

[
NONE,
{
at: (98, 65.7),
name: "Some city"
},
{
at: (-190.7, 0),
name: NONE
},
{
name: "Other city",
at: (0.0, 0.1)
},
{
name: "Nonexistent city",
at: (200.0, 66.5)
}
]
.filter(|$v| $v != NONE AND $v.name != NONE)
.filter(|$v| $v.at.is_valid())
.map(|$v, $i| {
item: $i,
name: $v.name,
coordinates: $v.at
});

Output

[
{
coordinates: (98, 65.7),
item: 0,
name: 'Some city'
},
{
coordinates: (0, 0.1),
item: 1,
name: 'Other city'
}
]

Was this page helpful?