View all results

Type ordering

FQL’s strict value ordering is deterministic. It is used by sorting, grouping, membership, deduplication, and structural value comparison. Any two values can be ordered, even when they do not have the same type.

When two values are compared, FQL first looks at their types. If the types are different, the result is decided by the global type order. The actual values are only compared when both operands have the same type.

FQL uses the following type order:

example.fql
read-only
NONE < bool < number < duration < string < datetime < binary < array < object

This means that NONE sorts before every other value, while objects sort after every other built-in value type.

For example, a boolean value always sorts before a number, duration, string, array, or object. A duration sorts after numbers and before strings, regardless of its nanosecond value.

example.fql
read-only
NONE < false NONE < 0 NONE < "" NONE < [] NONE < {} false < true true < 0 0 < "" 0 < "0" 0 < "abc" 0 < [] "" < "abc" "abc" < [] [] < {}

Once the types are the same, FQL compares the values according to the rules for that type.

Primitive values

Primitive values are ordered as follows:

  • NONE is only equal to NONE.
  • Booleans are ordered as false < true.
  • Numbers are ordered by numeric value.
  • Durations are ordered by their signed nanosecond value. In strict ordering they are distinct from numbers.
  • Strings are ordered using FQL’s string comparison rules.
example.fql
read-only
NONE == NONE false < true 1 < 2 10 > 2 500ms < 1s 1000ms == 1s "a" < "b"
Language comparison operators apply contextual conversion when a Duration is compared with a non-DateTime scalar. For example, 1ms == 1 is true because the number is interpreted as milliseconds. Strict consumers do not apply that conversion: DISTINCT [1, 1ms] keeps both values, and membership, sorting, and grouping preserve their different types.

DateTime comparison operators remain native-only. Two DateTime values compare by canonical instant; strings and numbers are not converted to DateTime for comparison.

NONE is a regular comparable value in FQL. Comparing a value with NONE does not produce an unknown result.

Arrays

Arrays are compared element by element from left to right.

At each position, FQL compares the two elements using the same comparison rules described on this page. If the elements are different, that result decides the array comparison. If the elements are equal, FQL moves to the next position.

If all compared elements are equal, the shorter array sorts first.

example.fql
read-only
[] < [0] [1] < [2] [false] < [true] [1, 2] < [1, 3] [1] < [1, 0]

Array comparison is recursive. If an element is another array or an object, that nested value is compared using the same rules.

example.fql
read-only
[[1]] < [[2]] [{ "score": 1 }] < [{ "score": 2 }]

Objects

Objects are compared by their attributes, not by the order in which those attributes were written.

Before two objects are compared, FQL considers their attribute names in sorted order. For each attribute name, FQL compares the corresponding values from both objects.

If one object has an attribute that the other object does not have, the missing value is treated as NONE for comparison purposes.

example.fql
read-only
{} < { "a": 1 } {} == { "a": NONE } { "a": 1 } < { "a": 2 } { "a": true } < { "a": 0 } { "a": { "score": 1 } } < { "a": { "score": 2 } }

Attribute declaration order does not affect equality:

example.fql
read-only
{ "a": 1, "b": 2 } == { "b": 2, "a": 1 }

If all attributes compare as equal, the objects are considered equal.

Next steps