Skip to content

Clauses

ORDER

To sort records, SurrealDB allows ordering on multiple fields and nested fields. Use the ORDER clause to specify a comma-separated list of field names that should be used to order the resulting records.

While not necessary to parse, the ORDER clause can be followed with BY to make queries more readable.

The ASC and DESC keywords can be used to specify whether results should be sorted in an ascending or descending manner. The COLLATE keyword can be used to use Unicode collation when ordering text in string values, ensuring that different cases, and different languages are sorted in a consistent manner. Finally, the NUMERIC can be used to correctly sort text which contains numeric values.

COLLATE can also be used to order by lexical instead of unicode order. For example, 'á' comes after 'z' by default (Unicode sorting) but with COLLATE 'á' comes before 'z'.

From SurrealDB 3.3, sort fields do not need to appear in the SELECT list. Sorting runs before projection, so you can order by a field that is omitted from the result:

-- Setup
CREATE audit_log:1 SET event = 'login', subject = 'tobie', at = d'2026-01-01T09:00:00Z';
CREATE audit_log:2 SET event = 'logout', subject = 'tobie', at = d'2026-01-01T17:00:00Z';

-- Sort by `at` without returning it
SELECT event, subject FROM audit_log ORDER BY at;

From SurrealDB 4.0, a sort key can also be a function call, which is evaluated for each record. To sort by the length of a name:

CREATE person:1 SET name = 'Boromir', age = 30;
CREATE person:2 SET name = 'Sam', age = 40;
CREATE person:3 SET name = 'Galadriel', age = 20;

SELECT name FROM person ORDER BY string::len(name) DESC;
Output
[
	{ name: 'Galadriel' },
	{ name: 'Boromir' },
	{ name: 'Sam' }
]

A function call is the way to sort by a field whose name is held in a parameter. ORDER BY $field does not parse, because a sort key is a field path or a function call, not a value. type::field() turns the name into the field, and a dotted path such as 'address.city' works as well:

-- Setup from the example above
CREATE person:1 SET name = 'Boromir', age = 30;
CREATE person:2 SET name = 'Sam', age = 40;
CREATE person:3 SET name = 'Galadriel', age = 20;

LET $field = 'age';
SELECT name FROM person ORDER BY type::field($field) DESC;
Output
[
	{ name: 'Sam' },
	{ name: 'Boromir' },
	{ name: 'Galadriel' }
]

An ordering by a vector distance function with a LIMIT, such as ORDER BY vector::distance::cosine(embedding, $vector) LIMIT 10, can be answered by a vector index. See ordering by distance.

Before SurrealDB 4.0, the clause takes field paths only, so ORDER BY string::len(name) does not parse. To sort on a computed value there, alias it in the SELECT list and order by that alias:

-- Setup from the example above
CREATE person:1 SET name = 'Boromir', age = 30;
CREATE person:2 SET name = 'Sam', age = 40;
CREATE person:3 SET name = 'Galadriel', age = 20;

SELECT name, string::len(name) AS length FROM person ORDER BY length DESC;

The sort direction cannot come from a parameter, so ASC or DESC is written in the query.

SPLIT and GROUP still require their fields to appear in the selection.

Clause Syntax
[ ORDER [ BY ] 
	@field | @function [ COLLATE ] [ NUMERIC ] [ ASC | DESC ], ...
	| RAND()
]
SELECT * FROM <table> ORDER BY <field> ASC;
-- Order records randomly
SELECT * FROM <table> ORDER BY rand();

-- Order records descending by a single field
SELECT * FROM <table> ORDER BY <field> DESC;

-- Order records by multiple fields independently
SELECT * FROM <table> ORDER BY <field> ASC, <field2> DESC;

-- Order text fields with lexical collation instead of Unicode order
SELECT * FROM <table> ORDER BY <field> COLLATE ASC;

-- Order text fields with which include numeric values
SELECT * FROM <table> ORDER BY <field> NUMERIC ASC;

-- COLLATE and NUMERIC can be used together
SELECT * FROM <table> ORDER BY <field> COLLATE NUMERIC ASC;

Was this page helpful?