GROQ

Current Working Draft

This is the specification for GROQ (Graph-Relational Object Queries), a query language and execution engine made at Sanity, Inc, for filtering and projecting JSON documents. The work started in 2015. The development of this open standard started in 2019.

GROQ is authored by Alexander Staubo and Simen Svale Skogsrud. Additional follow up work by Erik Grinaker, Magnus Holm, Radhe, Israel Roldan, Sindre Gulseth, Matt Craig, Espen Hovlandsdal.

This specification should be considered work in progress until the first release.

Conformance

A conforming implementation of GROQ must fulfill all normative requirements. Conformance requirements are described in this document via both descriptive assertions and key words with clearly defined meanings.

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in the normative portions of this document are to be interpreted as described in IETF RFC 2119. These key words may appear in lowercase and still retain their meaning unless explicitly declared as non‐normative.

A conforming implementation of GROQ may provide additional functionality, but must not where explicitly disallowed or would otherwise result in non‐conformance.

Conforming Algorithms

Algorithm steps phrased in imperative grammar (e.g. “Return the result”) are to be interpreted with the same level of requirement as the algorithm it is contained within. Any algorithm referenced within an algorithm step (e.g. “Let completedResult be the result of calling CompleteValue()”) is to be interpreted as having at least the same level of requirement as the algorithm containing that step.

Conformance requirements expressed as algorithms can be fulfilled by an implementation of this specification in any way as long as the perceived result is equivalent. Algorithms described in this document are written to be easy to understand. Implementers are encouraged to include equivalent but optimized implementations.

1Overview

GROQ (Graph-Relational Object Queries) is a declarative language designed to query collections of largely schema-less JSON documents. Its primary design goals are expressive filtering, joining of several documents into a single response, and shaping the response to fit the client application.

The idea behind GROQ is to be able to describe exactly what information your application needs, potentially joining together information from several sets of documents, then stitching together a very specific response with only the exact fields you need.

A query in GROQ typically starts with *. This asterisk represents every document in your dataset. It is typically followed by a filter in brackets. The filter take terms, operators and functions. A projection is wrapped in curly braces and describe the data as we want it returned.

Given these JSON documents:

{ "id": 1, "name": "Peter"}
{ "id": 2, "name": "Gamora"}
{ "id": 3, "name": "Drax"}
{ "id": 4, "name": "Groot"}
{ "id": 5, "name": "Rocket"}

The following query:

Example № 1*[id > 2]{name}

Will result in the following JSON document:

[
  { "name": "Drax"},
  { "name": "Groot"},
  { "name": "Rocket"}
]

2Syntax

A GROQ query is a string consisting of Unicode characters. The encoding of the query string is implementation-defined, but UTF-8 is the preferred choice. A query consist of a single Expression, with WhiteSpace and Comment allowed anywhere with no effect on the interpretation.

SourceCharacter
any Unicode character

2.1JSON Superset

GROQ’s syntax is a superset of JSON, so any valid JSON value is a valid GROQ expression (that simply returns the given value). Below are a few examples of JSON values:

"Hi! 👋"
["An", "array", "of", "strings"]
{
  "array": ["string", 3.14, true, null],
  "boolean": true,
  "number": 3.14,
  "null": null,
  "object": {"key": "value"},
  "string": "Hi! 👋"
}

2.2White Space

Whitespace is not significant in GROQ, except for acting as a token separator and comment terminator. Any sequence of the following characters is considered whitespace.

WhiteSpace
Tab U+0009
Newline U+000A
Vertical tab U+000B
Form feed U+000C
Carriage return U+000D
Space U+0020
Next line U+0085
Non-breaking space U+00A0

Whitespace inside a string literal is interpreted as-is.

2.3Comments

Comments serve as query documentation, and are ignored by the parser. They start with // and run to the end of the line:

Example № 2{
  // Comments can be on a separate line
  "key": "value" // Or at the end of a line
}

Comments cannot start inside a string literal.

Example № 3{
  "key // This isn't a comment": "value"
}

2.4Identifier

Identifiers are used to name entities such as parameters, attributes and functions. An identifier is a sequence of one or more letters and digits. The first character in an identifier must be a letter.

Identifier
/[A-Za-z\_][A-Za-z_0-9]\*/

2.5Digits

GROQ uses decimal digits (0-9) and hexadecimal digits (0-9, a-f) in various places.

Digit
0123456789
HexLetter
aAbBcCdDeEfF

2.6Expression

An Expression is either a literal (e.g. 15), a simple expression (e.g. @), or a compound expression (e.g. *[name == "Michael"]) or an operator call (e.g. name == "Michael"). The syntax and semantics of the different expressions are documented in their respective sections.

2.7Selector

A selector is a subset of an expression used to search for fields inside a document. They have their own evaluation logic (see EvaluateSelector()) which is used by certain functions.

3Execution

3.1Overview

Note The following sub-section is a non-normative overview of the execution model. See the rest of the section for the exact semantics.

A GROQ query is executed inside a query context, which contains the dataset and parameters, and returns a result. Typically the result is serialized to JSON. During the execution of a query different parts of the query are evaluated in different scopes. Each scope has a this value and can be nested. Simple attributes like name always refers to an attribute on the this value.

Example № 4*[_type == "person"]{name, friends[country == "NO"]}

In the preceding example we have several scopes:

  • The first filter ([_type == "person"]) creates a new scope for every document in the dataset. An equivalent scope is created inside the projection ({name, …}).
  • The country filter ([country == "NO"]) creates a new scope for each element in the friends array.

The parent expression (^) let’s you refer to parent scopes, and this enables what is typically solved with joins in many databases.

Example № 5*[_type == "person"]{
  id,
  name,
  "children": *[_type == "person" && parentId == ^.id]
}

While executing the inner filter ([_type == "person" && parentId == ^.id]) the expression ^.id returns the id attribute of the parent scope’s this value. The parent scope is here the scope created by the projection ({id, name, …}).

It’s possible for a query to be invalid. This can happen when you e.g. use an unknown function or call a function with incorrect number of arguments.

3.2Mode

Queries can be executed in two different modes: normal and delta. Delta mode is intended to be used in case where a change has been done to a document. In this mode you have the additional functionality of accessing the attributes before and after the change, and comparing the differences between them (using the functions in the delta-namespace).

3.3Query context

A query context consists of:

  • the dataset
  • parameter values (map from string to value)
  • the mode: either “normal” or “delta”

If the mode is “delta” then the query context also has:

  • a before object (which is null if this was a create-operation).
  • an after object (which is null if this was a delete-operation).

3.4Scope

A scope consists of:

  • a this value
  • an optional parent scope
  • a query context

A root scope can be constructed from a query context, and a nested scope can be constructed from an existing scope.

NewNestedScope(value, scope)
  1. Let newScope be a new scope.
  2. Set the this value of newScope to value.
  3. Set the parent scope of newScope to scope.
  4. Set the query context of newScope to the query context of scope.
  5. Return newScope.
NewRootScope(context)
  1. Let newScope be a new scope.
  2. Set the this value of newScope to null.
  3. Set the parent scope of newScope to null.
  4. Set the query context of newScope to context.
  5. Return newScope.

3.5Expression validation

An expression can be validated. This will only check that it’s on a valid form, and will not execute anything. If an expression type does not have an explicitly defined validator in this specification, it has an implicit validator which runs Validate on all its child expressions.

Validate(expr)
  1. Let validator be the validator of expr.
  2. Execute the validator.

3.6Expression evaluation

An expression is evaluated in a scope. You must successfully validate an expression before you attempt to evaluate it. Every expression type has their own evaluator function in their respective section in this specification (e.g. the evaluator of ParenthesisExpression is EvaluateParenthesis()).

Evaluate(expr, scope)
  1. Let evaluator be the evaluator of expr.
  2. Return the result of evaluator(scope).

3.7Constant expression evaluation

Some expressions can be evaluated into a constant value. This is used for validation and to disambiguate between different syntactically ambiguous expressions.

ConstantEvaluate(expr)
  1. If expr is one of: Literal, Parenthesis, Plus, Minus, Star, Slash, Percent, StarStar, UnaryPlus, UnaryMinus.
    1. Let evaluator be the evaluator of expr.
    2. Let result be the result of executing evaluator, but using ConstantEvaluate() in-place of every Evaluate().
    3. Return the result.
  2. Otherwise: Report an error.

3.8Score evaluation

When evaluating score, a predicate returning true should have its score computed as 1.0, and all other values should receive a score of 0.0. All results involved in scoring start with a score of 1.0. The scores are evaluated once per result, and then added together. For example:

Example № 6* | score(a > 1)

should assign a score of 2.0 to any document where a > 1, and a score of 1.0 to any non-matching document.

For logical expressions, the score is the sum of the clauses of the expression evaluates to true, otherwise 0.0. In other words:

  • true && false receives the score 0.0.
  • true && true receives the score 2.0.
  • true || true receives the score 2.0.
  • true || false receives the score 1.0.

The scoring function for match is left as an implementation detail and not covered by this specification. For example, an implementation may choose to use a TF/IDF or similar text scoring function that uses the text corpus and language configuration for the given field to compute a text score.

A boosted predicate simply adds the boost value to the score if the predicate matches. For example, boost(a > 1, 10) would result in a score of 11 for any expression matching a > 1.

3.9Selector evaluation

A selector (see Selector) is evaluated in a scope with a value and returns a list of key paths. A key path uniquely identifies a value by the attribute names and array indices used to access the value. For instance, the key path .users[1].name refers to the "Bob"-value in {"users":[{"name":"Alice"},{"name":"Bob"}]}.

EvaluateSelector(selector, value, scope)
  1. If selector is a SelectorGroup:
    1. Let inner be the inner selector.
    2. Return EvaluateSelector(inner, value).
  2. Let result be an empty list of key paths.
  3. If selector is a SelectorTuple:
    1. For each selector inner in the tuple:
      1. Let innerResult be the result of EvaluateSelector(inner, value, scope).
      2. Concatenate innerResult to result.
  4. If selector is a ThisAttibute:
    1. If value is an object which has the given attribute:
      1. Let keyPath be a new key path consisting of the attribute name.
      2. Append keyPath to result.
  5. If selector starts with a Selector:
    1. Let baseSelector be the selector.
    2. Let base be the result of EvaluateSelector(baseSelector, value, scope).
    3. For each keyPath in base:
      1. Let innerValue be the value at keyPath in value.
      2. If selector ends with a ArrayPostfix:
        1. If innerValue is an array:
          1. For each item in innerValue:
            1. Let nestedKeyPath be the result of combining keyPath with the array index.
            2. Append nestedKeyPath to result.
      3. If selector ends with a AttributeAccess:
        1. If innerValue is an object which has the given attribute:
          1. Let nestedKeyPath be the result of combining keyPath with the attribute name.
          2. Append nestedKeyPath to result.
      4. If selector ends with a Filter:
        1. If innerValue is an array:
          1. For each item of innerValue:
            1. Let nestedScope be the result of NewNestedScope(value, scope).
            2. Let matched be the result of Evaluate(expr, nestedScope).
            3. If matched is true:
              1. Let nestedKeyPath be the result of combining keyPath with the array index.
              2. Append nestedKeyPath to result.
      5. If selector ends with a SelectorGroup:
        1. Let inner be that selector.
        2. Let innerResult be the result of EvaluateSelector(inner, innerValue, scope).
        3. For each nestedKeyPath in innerResult:
          1. Let combinedKeyPath be the result of combining keyPath with nestedKeyPath.
          2. Append combinedKeyPath to result.
      6. If selector ends with a SelectorTuple:
        1. For each selector inner in the tuple:
          1. Let innerResult be the result of EvaluateSelector(inner, innerValue, scope).
          2. For each nestedKeyPath in innerResult:
            1. Let combinedKeyPath be the result of combining keyPath with nestedKeyPath.
            2. Append combinedKeyPath to result.
    4. Return result.

3.10Traversal execution

When working with JSON values you often need to access attributes in deeply nested arrays/objects. In JavaScript this is solved by using helper functions such as map, filter and flatMap. GROQ provides terse syntax for accomplishing the same functionality.

Example № 7// The following GROQ:
*[_type == "user"]._id

// is equivalent to the following JavaScript:
data.filter(u => u._type == "user").map(u => u._id)

The following expressions are implemented as a traversal:

When these traversals are combined (e.g. user.roles[0].permissions[priority > 2]{filter}) it triggers a separate traversal logic.

Informally the traversal logic is based on a few principles:

  • Traversal semantics are always statically known. The runtime value of an expression never impacts the overall interpretation of a traversal.
  • We categorize traversals into four types (plain, array, array source, array target) based on how they work on arrays. .user.name is considered a plain traversal because it statically only deals with plain values. [_type == "user"] is considered an array traversal because it works on arrays.
  • Placing a plain traversal next to an array traversals ([_type == "user"].name.firstName) will execute the plain traversal for each element of the array.

Formally the semantics are specified as follows:

  • Each traversal has a traverse function which describes how it will traverse a value. This function takes a value and a scope as parameters.
  • There’s a set of traversal combination functions which specifies how two traversals can be combined. This explains exactly how .user.name is mapped over each element of an array.
  • TraversalPlain, TraversalArray, TraversalArraySource, TraversalArrayTarget specifies the exact rules for how multiple traversals are combined together.
  • The TraversalExpression node is an Expression for the full set of traversal operators. This kicks off the whole traversal semantics.

3.10.1Combining traversal

Multiple traversals are combined in four different ways:

  • Joined: In .user.name we want to execute the first traversal (.user), and then apply the second traversal (.name) on the result. This is specified by the EvaluateTraversalJoin() function.
  • Mapped: In [_type == "user"].id we want to execute the first traversal ([_type == "user"]), and then apply the second traversal (.id) for each element of the array. This is specified by the EvaluateTraversalMap() function.
  • Flat-mapped: In [_type == "user"].names[] we want to execute the first traversal ([_type == "user"]), and then apply the second traversal (.names[]) for each element of the array, and then flatten the result. This is specified by the EvaluateTraversalFlatMap() function.
  • Inner mapped: In {name,type}[type == "admin"] we want to execute the first traversal ({name,type}) for each element of the array, and then apply the second traversal ([type == "admin"]) on the full array. This is specified by the EvaluateTraversalInnerMap() function.

Unless otherwise specified, any two traversal are combined using the EvaluateTraversalJoin() function.

EvaluateTraversalJoin(base, scope)
  1. Let traverse be the traverse function of the first node.
  2. Let nextTraverse be the traverse function of the last node.
  3. Let result to be the result of traverse(base, scope).
  4. Set result to be the result of nextTraverse(result, scope).
  5. Return result.
EvaluateTraversalMap(base, scope)
  1. Let traverse be the traverse function of the first node.
  2. Let nextTraverse be the traverse function of the last node.
  3. Set base to be the result of traverse(base, scope).
  4. If base is not an array:
    1. Return null.
  5. Let result be an empty array.
  6. For each value in base:
    1. Let elem be the result of nextTraverse(value, scope).
    2. Append elem to result.
  7. Return result.
EvaluateTraversalFlatMap(base, scope)
  1. Let traverse be the traverse function of the first node.
  2. Let nextTraverse be the traverse function of the last node.
  3. Set base to be the result of traverse(base, scope).
  4. If base is not an array:
    1. Return null.
  5. Let result be an empty array.
  6. For each value in base:
    1. Let elem be the result of nextTraverse(value, scope).
    2. If elem is an array:
      1. Concatenate elem to result.
  7. Return result.
EvaluateTraversalInnerMap(base, scope)
  1. Let traverse be the traverse function of the first node.
  2. Let nextTraverse be the traverse function of the last node.
  3. If base is not an array:
    1. Return null.
  4. Let result be an empty array.
  5. For each value in base:
    1. Let elem be the result of traverse(value, scope).
    2. Append elem to result.
  6. Set result to be the result of nextResult(base, scope).
  7. Return result.

3.10.2Plain traversal

A plain traversal is a traversal which works on and returns unknown types.

  • .user.name
  • .users[0].name
  • .image->{url}

The following are not considered plain traversals:

  • [_type == "user"].name (because it works on an array)
  • .users[] (because it returns an array)

3.10.3Array traversals

An array traversal is a traversal which statically is known to works on and return an array:

  • [_type == "user"].id
  • [_type == "user"].names[]
  • {name,type}[type == "admin"]

The following are not considered array traversals:

  • [_type == "user"].roles[0] (because it returns an unknown type)
  • .names[] (because it works on a non-array)

3.10.4Array source traversals

An array source traversal is a traversal which statically is known to work on an array, but returns an unknown type:

  • [0].user.name
  • [_type == "user"].roles[0]
  • {name,type}[0]

The following are not considered array source traversals:

  • [_type == "user"].id (because it returns an array)
  • .user.name (because it doesn’t work on an array)

3.10.5Array target traversals

An array target traversal is a traversal which statically is known to return on an array, but works on an unknown type:

  • user.roles[dataset == "production"]
  • {name,type}[]

The following are not considered array source traversals:

  • [_type == "user"].id (because it also works on an array)
  • .user.name (because it doesn’t work on an array)

3.11Query execution

To execute a query you must first construct a query context, and then evaluate the query expression inside a root scope.

ExecuteQuery(query, context)
  1. Let scope be the result of NewRootScope(context).
  2. Let expr be the expression of query.
  3. Let result be the result of Evalute(expr, scope).
  4. Return result.

4Data types

4.1Null

An unknown value, expressed as null. This follows the SQL definition of null, which differs from the typical definition of “no value” in programming languages, and implies among other things that 1 + null yields null (1 plus an unknown number yields an unknown number).

Null
null

4.2Boolean

Logical truth values, i.e. true and false.

Boolean
true
false

4.3Number

Signed 64-bit double-precision floating point numbers, e.g. 3.14, following the IEEE 754 standard. These have a magnitude of roughly 10⁻³⁰⁷ to 10³⁰⁸, and can represent 15 significant figures with exact precision – beyond this, significant figures are rounded to 53-bit precision. The special IEEE 754 values of Infinity and NaN are not supported, and are coerced to null.

Sign
+-

4.4String

A string stores an UTF-8 encoded list of characters.

The syntax of a string literal is a subset of JSON with the following extensions:

  • Any control characters (including newlines) are allowed to appear inside a string.
  • Extended support for referring to Unicode characters above 16-bit: "\u{1F600}".

Escape sequences are interpreted as follows:

  • \' represents U+0027.
  • \" represents U+0022.
  • \\ represents U+005C.
  • \/ represents U+002F.
  • \b represents U+0008.
  • \f represents U+000C.
  • \n represents U+000A.
  • \r represents U+000D.
  • \t represents U+0009.
  • \uXXXX represents the Unicode code point U+XXXX.
  • \uXXXX\uYYYY, where XXXX is a high surrogate (W1, 0xD800–0xDBFF) and YYYY is a low surrogate (W2, 0xDC00–0xDFFF) is interpreted as a UTF-16 surrogate pair and encoded into a single code point.

It’s a syntactical error when a Unicode escape sequence represents an invalid Unicode code point.

4.5Array

An ordered collection of values, e.g. [1, 2, 3]. Can contain any combination of other types, including other arrays and mixed types. An element inside an array literal can be preceded by ... which causes it to be flattened into the array.

EvaluateArray(scope)
  1. Let result be a new empty array.
  2. For each ArrayElement:
  3. Let elementNode be the Expression of the ArrayElement.
  4. Let element be the result of Evaluate(elementNode, scope).
  5. If the ArrayElement contains ...:
    1. If element is an array:
      1. Concatenate element to result.
  6. Otherwise:
    1. Append element to result.
  7. Return result.

4.6Object

An unordered collection of key/value pairs (referred to as attributes) with unique keys, e.g. {"a": 1, "b": 2}. Keys must be strings, while values can be any combination of other types, including other objects. If duplicate keys are specified, the last key is used.

The values of an object literal can use the full power of expressions:

Example № 8*[_type == "rect"]{"area": width * height}
Note A Projection expression is just an expression with an object literal to the right of it.

Object literal supports syntactical sugar when the attribute name and value is equivalent:

Example № 9// These two are equivalent
*[_type == "person"]{name}
*[_type == "person"]{"name": name}
EvaluateObject(scope)
  1. Let result be a new empty object.
  2. For each ObjectAttribute:
    1. If the ObjectAttribute contains ...:
      1. If the ObjectAttribute contains an Expression:
        1. Let baseNode be the Expression.
      2. Let base be the result of Evaluate(baseNode, scope).
      3. Otherwise:
        1. Let base be the this value of scope.
      4. For each name and value of base:
        1. Set the attribute name to value in result.
    2. Otherwise:
      1. Let valueNode be the Expression of the ObjectAttribute.
      2. Let value be the result of Evaluate(valueNode, scope).
      3. If the ObjectAttribute contains a String:
        1. Let name be the string value of the String.
      4. Otherwise:
        1. Let name be the result of DetermineName(valueNode).
      5. Set the attribute name to value in result.
  3. Return result.
DetermineName(node)
  1. If node is an ThisAttribute:
    1. Return the string value of the Identifier of node.
  2. If node is a ArrayPostfix, Dereference, ElementAccess, Filter, Map, Projection, SelectorGroup, or Slice:
    1. Let base be the first Expression of expr.
    2. Return the result of DetermineName(base).
ValidateObject()
  1. For each ObjectAttribute:
    1. If the ObjectAttribute does not contain a String:
      1. Let expr be the Expression.
      2. Execute ValidateObjectAttribute(expr).
ValidateObjectAttribute(expr)
  1. If node is an ThisAttribute:
    1. Stop.
  2. If node is a Projection, ElementAccess, Slice, or Filter:
    1. Let base be the first Expression of expr.
    2. Execute ValidateObjectAttribute(base).
  3. Otherwise:
    1. Report an error.

4.7Pair

A pair of values, e.g. "a" => 1. Pairs can contain any combination of other types, including other pairs, and are mainly used internally with e.g. projection conditionals andselect().

In serialized JSON, pairs are represented as a string on the form fst => snd where fst and snd are the serialized JSON for the first and the second expression.

EvaluatePair(scope)
  1. Let firstNode be the first Expression.
  2. Let secondNode be the second Expression.
  3. Let result be a new pair.
  4. Set the first value of result to the result of Evaluate(firstNode, scope).
  5. Set the second value of result to the result of Evaluate(secondNode, scope).
  6. Return result.

4.8Range

An interval containing all values that are ordered between the start and end values. The starting value is always included, while the end may be either included or excluded. A right-inclusive range is expressed as two values separated by .., e.g. 1..3, while a right-exclusive range is separated by ..., e.g. 1...3.

Ranges can have endpoints of any comparable data type, but both endpoints must be of the same type (except integers and floats which can be used interchangeably). Ranges with incompatible or invalid endpoints types will yield null.

Ranges are mainly used internally, e.g. with the in operator and array slice access operator. The endpoints may have context-dependent semantics, e.g. in array slices the range [2..-1] will cover the range from the third array element to the last element, while the same range is considered empty when used with in. For more details, see the documentation for the relevant operators.

In serialized JSON, ranges are represented as a string on the form start..end (for inclusive ranges) and start...end (for exclusive ranges) where start and end are the serialized JSON for the start and the end expression.

EvaluateRange(scope)
  1. Let startNode be the first Expression.
  2. Let endNode be the second Expression.
  3. Let start be the result of Evaluate(startNode, scope).
  4. Let end be the result of Evaluate(endNode, scope).
  5. If PartialCompare(start, end) is null:
    1. Return null.
  6. Let result be a new range.
  7. Set the start value of result to start.
  8. Set the end value of result to end.
  9. Mark the range as inclusive or exclusive.
  10. Return result.

4.9Datetime

A datetime is a combination of a Gregorian-calendar date and a time in UTC. It’s stored in millisecond precision, but an implementation can choose to support even finer granularity. Datetimes support date/time arithmetic. Only valid date/time combinations can be represented.

Datetimes cannot be constructed from literals, but must be constructed with the dateTime function.

In serialized JSON, datetimes are represented as a string with using RFC 3339 timestamp format, e.g. 2006-01-02T15:04:05Z using the following rules:

  1. If there is no millisecond information in the datetime, format it without any fractional digits: 2006-01-02T15:04:05Z
  2. If there is millisecond information in the datetime, format it with 3 fractional digits: 2006-01-02T15:04:05.508Z
  3. If the datetime contains even finer granularity, it’s implementation dependent how the additional fractional digits are formatted.

5Equality and comparison

GROQ provides trivial equality and comparison between numbers, strings and booleans. Other types are considered inequal or incomparable to each other. Incomparability between values are represented by operators returning null (e.g. 2 > "1" is null).

5.1Equality

Simple values such as numbers, strings, booleans and null are equal when they contain the same data. All other values are considered inequal to each other (e.g. [] != []).

Note In GROQ 1 == null returns false (which is different from e.g. SQL).
Equal(a, b)
  1. If both a and b is null:
    1. Return true.
  2. Let cmp be the result of PartialCompare(a, b).
  3. If cmp is Equal:
    1. Return true.
  4. Otherwise:
    1. Return false.

5.2Partial comparison

A partial comparison between two values return either Greater, Equal, Less or null. null represents that the values are incomparable to each other. This is used by the comparison operators (<, ≤, >, ≥).

PartialCompare(a, b)
  1. If the type of a is different from the type of b:
    1. Return null.
  2. If a is a datetime, consider the datetimes as absolute points in time in the UTC time zone:
    1. If a < b:
      1. Return Less.
    2. If a > b:
      1. Return Greater.
    3. If a = b:
      1. Return Equal.
  3. If a is a number:
    1. If a < b:
      1. Return Less.
    2. If a > b:
      1. Return Greater.
    3. If a = b:
      1. Return Equal.
  4. If a is a string:
    1. For each Unicode code point (aCodePoint, bCodePoint) in a and b:
      1. If aCodePoint < bCodePoint:
        1. Return Less.
      2. If aCodePoint > bCodePoint: * Return Greater.
    2. If a is shorter than b:
      1. Return Less.
    3. If a is longer than b:
      1. Return Greater.
    4. Return Equal.
  5. If a is a boolean:
    1. Return the comparison between a and b with false < true.
  6. Return null.

5.3Total comparison

A total comparison between two values return either Greater, Equal or Less. It provides a consistent ordering of values of different types (for string, numbers and boolean) and considers all other types to be equal to each other. This is used by the order() function.

TypeOrder(val)
  1. If val is a datetime:
    1. Return 1.
  2. If val is a number:
    1. Return 2.
  3. If val is a string:
    1. Return 3.
  4. If val is a boolean:
    1. Return 4.
  5. Return 5.
TotalCompare(a, b)
  1. Let aTypeOrder be the result of TypeOrder(a).
  2. Let bTypeOrder be the result of TypeOrder(b).
  3. If aTypeOrder != bTypeOrder:
    1. Return the result of PartialCompare(aTypeOrder, bTypeOrder).
  4. Let result be the result of PartialCompare(a, b).
  5. If result is null:
    1. Return Equal.
  6. Otherwise:
    1. Return result.

6Simple expressions

6.1This expression

A this expression returns the this value of the current scope.

Example № 10*[_id == "doc"][0].numbers[@ >= 10]
                           ~
This
@
EvaluateThis(scope)
  1. Return the this value of scope.

6.2This attribute expression

A this attribute expression returns an attribute from the this value of the current scope.

Example № 11*[_id == "document"][name == "Michael Bluth"]
  ~~~                ~~~~
EvaluateThisAttribute(scope)
  1. Let base be the this value of scope.
  2. Let name be the string value of the Identifier.
  3. If base is not an object, return null.
  4. If base does not contain an attribute name, return null.
  5. Return the value of the attribute name in base.

6.3Everything expression

An everything expression returns the full dataset.

Example № 12*[_type == "person"]
~
EvaluateEverything(scope)
  1. Let context be the query context of scope.
  2. Return the dataset of context.

6.4Parent expression

A parent expression returns a this value for an upper scope.

Example № 13// Find all people who have a cool friend
*[_type == "person" && *[_id == ^.friend._ref][0].isCool]
                                ~
EvaluateParent(scope)
  1. Let level be the number of ^ in the parent expression.
  2. Let currentScope be scope.
  3. While level is greater than zero:
    1. Set currentScope to the parent of currentScope.
    2. If currentScope is now null, return null.
    3. Decrease level by one.
  4. Return the this value of currentScope.

6.5Function call expression

GROQ comes with a set of built-in functions which provides additional features. See the “Functions” for available functions and their namespaces.

Example № 14*{"score": round(score, 2)}
           ~~~~~~~~~~~~~~~

*{"description": global::lower(description)}
                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
EvaluateFuncCall(scope)
  1. Let namespace be the string value of the FuncNamespace.
  2. Let name be the string value of the FuncIdentifier.
  3. Let args be an empty array.
  4. For each Expression in FuncCallArgs:
    1. Let argumentNode be the Expression.
    2. Append argumentNode to args.
  5. Let func be the function defined under the name name in either namespace namespace if provided, or the global namespace.
  6. Return the result of func(args, scope).
ValidateFuncCall()
  1. Let namespace be the string value of the FuncNamespace.
  2. If there is no namespace named namespace:
    1. Stop and report an error.
  3. Let name be the string value of the FuncIdentifier.
  4. If there is no function named name defined in either namespace namespace if provided, or the global namespace:
    1. Stop and report an error.
  5. Let args be an array of the Expressions in FuncCallArgs.
  6. Let validator be the validator for the function under the name name.
  7. Execute validator(args).

7Compound expressions

7.1Parenthesis expression

A parenthesis expression allows you to add parenthesis around another expression to control precedence of operators.

Example № 15(1 + 2) * 3
~~~~~~~
EvaluateParenthesis(scope)
  1. Let innerNode be the Expression.
  2. Let result be the result of Evaluate(innerNode, scope).
  3. Return result.

7.2Traversal expression

A traversal expressions starts a traversal.

Example № 16users.foo.bar[0].sources[]->name

When the left-hand side is an Everything, Array, or PipeFuncCall this is interpreted as if there was an additional explicit ArrayPostfix traversal. E.g. *._id is interpreted as *[]._id and therefore returns an array of IDs.

EvaluateTraversalExpression(scope)
  1. Let node be the Expression.
  2. Let traversalNode be the Traversal.
  3. Let base be the result of Evaluate(node, scope).
  4. If node is one of Everything, Array, PipeFuncCall:
    1. Let traverse be the traversal function for the combination ArrayPostfix and traversalNode.
  5. Otherwise:
    1. Let traverse be the traverse function of traversalNode.
  6. Return traverse(base, scope).

7.3Pipe function call expression

GROQ comes with a set of built-in pipe functions which provides additional features. Pipe functions always accepts an array on the left-hand side and returns another array, and the syntax is optimized for being able to chain it together with other compound expressions. See the “Pipe functions” for available functions.

Example № 17*[_type == "person"] | order(name) | {age}
                     ~~~~~~~~~~~~~
EvaluatePipeFuncCall(scope)
  1. Let baseNode be the first Expression.
  2. Let base be the result of Evaluate(baseNode, scope).
  3. If base is not an array:
    1. Return null.
  4. Let name be the string value of the Identifier of the FuncCall.
  5. Let args be an empty array.
  6. For each Expression in the FuncCallArgs of the FuncCall.
    1. Let argumentNode be the Expression.
    2. Append argumentNode to args.
  7. Let func be the pipe function defined under the name name.
  8. Return the result of func(base, args, scope).
ValidatePipeFuncCall()
  1. Let base be the first Expression.
  2. Execute Validate(base).
  3. Let name be the string value of the Identifier of the FuncCall.
  4. If there is no pipe function named name:
    1. Stop and report an error.
  5. Let args be an array of the Expressions in the FuncCallArgs of the FuncCall.
  6. Let validator be the validator for the pipe function under the name name.
  7. Execute validator(args).

8Traversal operators

8.1Attribute access traversal

An attribute access returns an attribute of an object.

Example № 18person.name
      ~~~~~

person["Full Name"]
      ~~~~~~~~~~~~~
Note Filter, ElementAccess, AttributeAccess are syntactically ambiguous. See “Disambiguating square bracket traversal” for how to disambiguate between them.
EvaluateAttributeAccess(base, scope)
  1. If base is not an object, return null.
  2. Let name be the string value of String or Identifier.
  3. If base does not contain an attribute name, return null.
  4. Return the value of the attribute name in base.

8.2Element access traversal

An element access returns an element stored in an array. The array is 0-indexed and a negative index accesses the array from the end (i.e. an index of -1 returns the last element; -2 refers to the second last element).

Note Filter, ElementAccess, AttributeAccess are syntactically ambiguous. See “Disambiguating square bracket traversal” for how to disambiguate between them.
EvaluateElementAccess(base, scope)
  1. If base is not an array, return null.
  2. Let idxNode be the second Expression.
  3. Let idx be the result of Evaluate(idxNode, scope). This value is guaranteed to be an integer due to the validation.
  4. If idx is negative, add the length of base to idx.
  5. If idx is still negative, return null.
  6. If idx is equal to or greater than the length of base, return null.
  7. Return the value stored at position idx in base.
ValidateElementAccess()
  1. Let idxNode be the second Expression.
  2. Let idx be the result of ConstantEvaluate(idxNode). This value is guaranteed to be a number due to square bracket disambiguation.
  3. If idx is not an integer: Report an error.

8.3Slice traversal

A slice returns a slice of an array.

Example № 19people[0..10]
      ~~~~~~~
EvaluateSlice(base, scope)
  1. Let base be the result of Evaluate(baseNode, scope).
  2. If base is not an array, return null.
  3. Process the left index:
    1. Let leftNode be the left value of the Range.
    2. Let left be the result of Evaluate(leftNode, scope). This value is guaranteed to be an integer due to the validation.
    3. If left is negative, add the length of base to left.
    4. Clamp left between 0 and (the length of base minus 1).
  4. Process the right index:
    1. Let rightNode be the right value of the Range.
    2. Let right be the result of Evaluate(rightNode, scope). This value is guaranteed to be an integer due to the validation.
    3. If right is negative, add the length of base to right.
    4. If the Range is exclusive, subtract one from right.
    5. Clamp right between 0 and (the length of base minus 1).
  5. Let result be an array containing the elements of base from position left up to and including position right.
  6. Return result.
ValidateSlice()
  1. Let leftNode be the left value of the Range.
  2. Let leftValue be the result of ConstantEvaluate(leftNode).
  3. If leftValue is not an integer: Report an error.
  4. Let rightNode be the right value of the Range.
  5. Let rightValue be the result of ConstantEvaluate(rightNode).
  6. If rightValue is not an integer: Report an error.

8.4Filter traversal

A filter returns an array filtered another expression.

Example № 20*[_type == "person"]
 ~~~~~~~~~~~~~~~~~~~
Note Filter, ElementAccess, AttributeAccess are syntactically ambiguous. See “Disambiguating square bracket traversal” for how to disambiguate between them.
EvaluateFilter(base, scope)
  1. If base is not an array, return base.
  2. Let filterNode be the second Expression.
  3. Let result be a new empty array.
  4. For each element value in baseValue:
    1. Let elementScope be the result of NewNestedScope(value, scope).
    2. Let matched be the result of Evaluate(filterNode, elementScope).
    3. If matched is true, append value to result.
  5. Return result.

8.5Array postfix traversal

An array postfix coerces the value into an array.

EvaluateArrayPostfix(base, scope)
  1. If base is not an array, return null.
  2. Return base.

8.6Projection traversal

A projection operator returns a new object.

Example № 21*[_type == "person"]{name, "isLegal": age >= 18}
                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
EvaluateProjection(base, scope)
  1. Let objNode be the Object.
  2. If base is not an object:
    1. Return null.
  3. Let elementScope be the result of NewNestedScope(base, scope).
  4. Let result be the result of Evaluate(objNode, elementScope).
  5. Return result.

8.7Dereference traversal

EvaluateDereference(base, scope)
  1. If base is not an object:
    1. Return null.
  2. If base does not have an attribute _ref:
    1. Return null.
  3. Let ref be the value of the attribute _ref in base.
  4. If ref is not a string:
    1. Return null.
  5. Let dataset be the dataset of the query context of scope.
  6. If dataset is not an array:
    1. Return null.
  7. Let result be null.
  8. For each document in dataset:
    1. If document is an object and has an attribute _id:
      1. Let id be the value of the attribute _id in document.
      2. If Equal(ref, id) is true:
        1. Set result to document.
        2. Stop the loop.
  9. If the dereference expression contains a Identifier:
    1. Let name be the string value of the Identifier.
    2. If result is an object and contains an attribute name:
      1. Return the value of the attribute name in result.
    3. Otherwise:
      1. Return null.
  10. Return result.

8.8Disambiguating square bracket traversal

Filter, ElementAccess and AttributeAccess are syntactically ambiguous, and the following algorithm is used to disambiguate between them.

DisambiguateSquareBracketTraversal()
  1. Let valueNode be the Expression.
  2. Let value be the result of ConstantEvaluate(valueNode).
  3. If value is a string: Interpret it as an AttributeAccess traversal.
  4. If value is a number: Interpret it as an ElementAccess traversal.
  5. Otherwise: Interpret it as a Filter traversal.

9Operators

9.1And operator

EvaluateAnd(scope)
  1. Let leftNode be the first Expression.
  2. Let left be the result of Evaluate(leftNode, scope).
  3. Let rightNode be the last Expression.
  4. Let right be the result of Evaluate(rightNode, scope).
  5. If left or right is false:
    1. Return false.
  6. If left or right is not a boolean:
    1. Return null.
  7. Return true.

9.2Or operator

EvaluateOr(scope)
  1. Let leftNode be the first Expression.
  2. Let left be the result of Evaluate(leftNode, scope).
  3. Let rightNode be the last Expression.
  4. Let right be the result of Evaluate(rightNode, scope).
  5. If left or right is true:
    1. Return true.
  6. If left or right is not a boolean:
    1. Return null.
  7. Return false.

9.3Not operator

EvaluateNot(scope)
  1. Let valueNode be the Expression.
  2. Let value be the result of Evaluate(valueNode, scope).
  3. If value is false:
    1. Return true.
  4. If value is true:
    1. Return false.
  5. Return null.

9.4Equality operators

EvaluateEquality(scope)
  1. Let leftNode be the first Expression.
  2. Let left be the result of Evaluate(leftNode, scope).
  3. Let rightNode be the last Expression.
  4. Let right be the result of Evaluate(rightNode, scope).
  5. Let result be the result of Equal(left, right).
  6. If the operator is !=:
    1. If result is true:
      1. Return false.
    2. If result is false:
      1. Return true.
  7. Return result.

9.5Comparison operators

ComparisonOperator
<,<=,>,>=
EvaluateComparison(scope)
  1. Let leftNode be the first Expression.
  2. Let left be the result of Evaluate(leftNode, scope).
  3. Let rightNode be the last Expression.
  4. Let right be the result of Evaluate(rightNode, scope).
  5. Let cmp be the result of PartialCompare(left, right).
  6. If cmp is null:
    1. Return null.
  7. If cmp is Less and the operator is < or <=:
    1. Return true.
  8. If cmp is Greater and the operator is > or >=:
    1. Return true.
  9. If cmp is Equal and the operator is <= or >=:
    1. Return true.
  10. Return false.

9.6In operator

EvaluateIn(scope)
  1. Let leftNode be the first Expression.
  2. Let left be the result of Evaluate(leftNode, scope).
  3. If the right-hand side is a Range:
    1. Let lowerNode be the start node of the range.
    2. Let lower be the result of Evaluate(lowerNode, scope).
    3. Let upperNode be the end node of the range.
    4. Let upper be the result of Evaluate(upperNode, scope).
    5. Let leftCmp be the result of PartialCompare(left, lower).
    6. Let rightCmp be the result of PartialCompare(left, upper).
    7. If leftCmp or rightCmp is null:
      1. Return null.
    8. If leftCmp is Less:
      1. Return false.
    9. If rightCmp is Greater:
      1. Return false.
    10. If the range is exclusive and rightCmp is Equal:
      1. Return false.
    11. Return true.
  4. Let rightNode be the last Expression.
  5. Let right be the result of Evaluate(rightNode, scope).
  6. If right is an array:
    1. For each value in right:
      1. If Equal(left, value) is true:
        1. Return true.
    2. Return false.
  7. Return null.

9.7Match operator

The match operator is defined in terms of patterns and tokens: It returns true when any of patterns matches all of the tokens. The exact way of tokenizing text and interpreting patterns is left as an implementation detail.

EvaluateMatch(scope)
  1. Let leftNode be the first Expression.
  2. Let left be the result of Evaluate(leftNode, scope).
  3. Let rightNode be the last Expression.
  4. Let right be the result of Evaluate(rightNode, scope).
  5. Let tokens be an empty array.
  6. If left is a string:
    1. Concatenate MatchTokenize(left) to tokens.
  7. If left is an array:
    1. For each value in left:
      1. If value is a string:
        1. Concatenate MatchTokenize(value) to tokens.
  8. Let patterns be an empty array.
  9. If right is a string:
    1. Append MatchAnalyzePattern(right) to patterns.
  10. If right is an array:
    1. For each value in right:
      1. If value is a string:
        1. Append MatchAnalyzePattern(value) to patterns.
      2. Otherwise: * Return false.
  11. If patterns is empty:
    1. Return false.
  12. For each pattern in patterns:
    1. If pattern does not matches tokens:
      1. Return false.
  13. Return true.
MatchTokenize(value)
  1. Return an array of tokens.
MatchAnalyzePattern(value)
  1. Return a pattern for the given string.

9.8Asc operator

The asc operator is used by the order() function to signal that you want ascending sorting. Evaluating it in any other context is not allowed.

ValidateAsc()
  1. Report an error.

9.9Desc operator

The desc operator is used by the order() function to signal that you want descending sorting. Evaluating it in any other context is not allowed.

ValidateDesc()
  1. Report an error.

9.10Unary plus operator

EvaluateUnaryPlus(scope)
  1. Let valueNode be the Expression.
  2. Let value be the result of Evaluate(valueNode, scope).
  3. If value is a number:
    1. Return value.
  4. Return null.

9.11Unary minus operator

EvaluateUnaryMinus(scope)
  1. Let valueNode be the Expression.
  2. Let value be the result of Evaluate(valueNode, scope).
  3. If value is a number:
    1. Return value with opposite sign.
  4. Return null.

9.12Binary plus operator

EvaluatePlus(scope)
  1. Let leftNode be the first Expression.
  2. Let left be the result of Evaluate(leftNode, scope).
  3. Let rightNode be the last Expression.
  4. Let right be the result of Evaluate(rightNode, scope).
  5. If both left and right are strings:
    1. Return the string concatenation of left and right.
  6. If both left and right are numbers:
    1. Return the addition of left and right.
  7. If both left and right are arrays:
    1. Return the concatenation of left and right.
  8. If both left and right are objects:
    1. Return the merged object of left and right. For duplicate fields the value from right takes precedence.
  9. If left is a datetime and right is a number:
    1. Return a new datetime that adds (or subtracts, if negative) right as a number of seconds to left.
  10. Return null.

9.13Binary minus operator

EvaluateMinus(scope)
  1. Let leftNode be the first Expression.
  2. Let left be the result of Evaluate(leftNode, scope).
  3. Let rightNode be the last Expression.
  4. Let right be the result of Evaluate(rightNode, scope).
  5. If both left and right are numbers:
    1. Return the subtraction of left from right.
  6. If both left and right are datetimes:
    1. Return the difference, in seconds, between left from right.
  7. If left is a datetime and right is a number:
    1. Return a new datetime being left minus right as seconds.
  8. Return null.

9.14Binary star operator

EvaluateStar(scope)
  1. Let leftNode be the first Expression.
  2. Let left be the result of Evaluate(leftNode, scope).
  3. Let rightNode be the last Expression.
  4. Let right be the result of Evaluate(rightNode, scope).
  5. If both left and right are numbers:
    1. Return the multiplication of left and right.
  6. Return null.
Note A binary star operator may not have a * immediately following it since this may cause ambiguity.

9.15Binary slash operator

EvaluateSlash(scope)
  1. Let leftNode be the first Expression.
  2. Let left be the result of Evaluate(leftNode, scope).
  3. Let rightNode be the last Expression.
  4. Let right be the result of Evaluate(rightNode, scope).
  5. If both left and right are numbers:
    1. Return the division of left by right.
  6. Return null.

9.16Binary percent operator

EvaluatePercent(scope)
  1. Let leftNode be the first Expression.
  2. Let left be the result of Evaluate(leftNode, scope).
  3. Let rightNode be the last Expression.
  4. Let right be the result of Evaluate(rightNode, scope).
  5. If both left and right are numbers:
    1. Return the remainder of left after division by right.
  6. Return null.

9.17Binary double star operator

EvaluateStarStar(scope)
  1. Let leftNode be the first Expression.
  2. Let left be the result of Evaluate(leftNode, scope).
  3. Let rightNode be the last Expression.
  4. Let right be the result of Evaluate(rightNode, scope).
  5. If both left and right are numbers:
    1. Return the exponentiation of left to the power of right.
  6. Return null.

10Precedence and associativity

In this specification the various expressions and operators are defined in ambiguously in terms on precedence and associativity. The table below describes the precedence levels used to determine the correct unambiguous interpretation.

From highest to lowest:

11Functions

Functions provide additional functionality to GROQ queries. They are invoked through a Function call expression. Note that function arguments are not evaluated eagerly, and it’s up to the function to decide which scope the arguments are evaluated it. As such, all functions below take an array of nodes.

An implementation may provide additional functions, but should be aware that this can cause problems when interoperating with future versions of GROQ.

Functions are namespaced which allows to group functions by logical scope. A function may be associated with multiple namespaces and behave differently. When a function is called without a namespace, it is by default associated with a “global” namespace.

11.1Global namespace

11.1.1global::after()

The after function, in delta mode, returns the attributes after the change.

global_after(args, scope)
  1. Return the after object of the query context of scope.
global_after_validate(args, scope)
  1. If the length of args is not 0:
    1. Report an error.
  2. If the mode of the query context of scope is not “delta”:
    1. Report an error.

11.1.2global::before()

The before function, in delta mode, returns the attributes before the change.

global_before(args, scope)
  1. Return the before object of the query context of scope.
global_before_validate(args, scope)
  1. If the length of args is not 0:
    1. Report an error.
  2. If the mode of the query context of scope is not “delta”:
    1. Report an error.

11.1.3global::coalesce()

The coalesce function returns the first value of the arguments which is not null.

global_coalesce(args, scope)
  1. For each arg in args:
    1. Let value be the result of Evaluate(arg, scope).
    2. If value is not null:
      1. Return value.
  2. Return null.

11.1.4global::count()

The count function returns the length of an array.

global_count(args, scope)
  1. Let baseNode be the first element of args.
  2. Let base be the result of Evaluate(baseNode, scope).
  3. If base is an array:
    1. Return the length of base.
  4. Otherwise:
    1. Return null.
global_count_validate(args)
  1. If the length of args is not 1:
    1. Report an error.

11.1.5global::dateTime()

The dateTime function takes a string or another datatime value, returning a datetime value. This function is idempotent.

global_dateTime(args, scope)
  1. Let baseNode be the first element of args.
  2. Let base be the result of Evaluate(baseNode, scope).
  3. If base is a string:
    1. Try to parse base as a datetime using the RFC 3339 timestamp format.
    2. If the input is a valid datetime:
      1. Return the datetime.
  4. If base is a datetime value:
    1. Return base.
  5. Return null.
global_dateTime_validate(args)
  1. If the length of args is not 1:
    1. Report an error.

11.1.6global::defined()

The defined function checks if the argument is not null.

global_defined(args, scope)
  1. Let baseNode be the first element of args.
  2. Let base be the result of Evaluate(baseNode, scope).
  3. If base is null:
    1. Return false.
  4. Otherwise:
    1. Return true.
global_defined_validate(args)
  1. If the length of args is not 1:
    1. Report an error.

11.1.7global::length()

The length function returns the length of a string or an array.

global_length(args, scope)
  1. Let baseNode be the first element of args.
  2. Let base be the result of Evaluate(baseNode, scope).
  3. If base is a string:
    1. Return the length of base.
  4. If base is an array:
    1. Return the length of base.
  5. Return null.
global_length_validate(args)
  1. If the length of args is not 1:
    1. Report an error.

11.1.8global::now()

The now function returns the current point in time as a string.

Note This function returns a string due to backwards compatibility. It’s recommended to use dateTime::now() instead which returns a proper datetime.
global_now(args, scope)
  1. Let ts be a datetime representing the current point in time.
  2. Let result be a RFC 3339 string formatting of ts.
  3. Return result.
global_now_validate(args)
  1. If the length of args is not 0:
    1. Report an error.

11.1.9global::references()

The references function implicitly takes this value of the current scope and recursively checks whether it contains any references to the given document ID.

global_references(args, scope)
  1. Let pathSet be an empty array.
  2. For each arg of args:
    1. Let path be the result of Evaluate(arg, scope).
    2. If path is a string:
      1. Append path to pathSet.
    3. If path is an array:
      1. Concatenate all strings of path to pathSet.
  3. If pathSet is empty:
    1. Return false.
  4. Let base be the this value of scope.
  5. Return the result of HasReferenceTo(base, pathSet).
HasReferenceTo(base, pathSet)
  1. If base is an array:
    1. For each value in base:
      1. Let result be the result of HasReferenceTo(value, pathSet).
      2. If result is true:
        1. Return true.
    2. Return false.
  2. If base is an object:
    1. If base has an attribute _ref:
      1. Let ref be the value of the attribute _ref in base.
      2. If ref exists in pathSet:
        1. Return true.
      3. Otherwise:
        1. Return false.
    2. For each key and value in base:
      1. Let result be the result of HasReferenceTo(value, pathSet).
      2. If result is true:
        1. Return true.
  3. Return false.
global_references_validate(args)
  1. If the length of args is 0:
    1. Report an error.

11.1.10global::round()

The round function accepts a number and rounds it to a certain precision.

global_round(args, scope)
  1. Let numNode be the first element of args.
  2. Let num be the result of Evaluate(numNode, scope).
  3. If num is not a number:
    1. Return null.
  4. If the length of args is 2:
    1. Let precNode be the second element of args.
    2. Let prec be the result of Evaluate(precNode, scope).
    3. If prec is not a number:
      1. Return null.
  5. Otherwise:
    1. Let prec be 0.
  6. Return num rounded to prec number of digits after the decimal point.
global_round_validate(args)
  1. If the length of args is less than 1 or greater than 2:
    1. Report an error.

11.1.11global::select()

The select function chooses takes a variable number of arguments that are either pairs or any other type and iterates over them. When encountering a pair whose left-hand value evaluates to true, the right-hand value is returned immediately. When encountering a non-pair argument, that argument is returned immediately. Falls back to returning null.

global_select(args, scope)
  1. For each arg in args:
    1. If arg is a Pair:
      1. Let condNode be the first Expression of the Pair.
      2. Let resultNode be the second Expression of the Pair.
      3. Let cond be the result of Evaluate(condNode, scope).
      4. If cond is true:
        1. Return the result of Evaluate(resultNode, scope).
    2. Otherwise:
      1. Return the result of Evaluate(arg, scope).
global_select_validate(args)
  1. Let seenDefault be false.
  2. For each arg in args:
    1. If seenDefault is true:
      1. Report an error.
    2. If arg is not a Pair:
      1. Set seenDefault to true.

11.1.12global::string()

The string function returns the string representation of scalar values or null for any other values.

global_string(args, scope)
  1. Let node be the first element of args.
  2. Let val be the result of Evaluate(node, scope).
  3. If val is true:
    1. Return the string "true".
  4. If val is false:
    1. Return the string "false".
  5. If val is a string:
    1. Return val.
  6. If val is a number:
    1. Return a string representation of the number.
  7. If val is a datetime:
    1. Return the datetime in the RFC 3339 timestamp format with a Z suffix.
  8. Otherwise:
    1. Return null.
global_string_validate(args)
  1. If the length of args is not 1:
    1. Report an error.

11.1.13global::boost()

The boost function accepts an expression and a boost value, and increases or decreases the score computed by score() (see “Pipe functions”) accordingly. boost can only be used within the argument list to score().

Example № 22* | score(boost(title matches "milk", 5.0), body matches "milk")

The expression must be a predicate expressions that evaluates to a single boolean value. Any other result value is ignored.

The value argument must be a number ≥ 0.

The return value is the same as the input predicate. Internally, the scoring execution model uses the provided boost value to increase the computed score if the predicate matches.

boost(args, scope)
  1. Let predicateNode be the first element of args.
  2. Let result be the result of Evaluate(predicateNode, scope).
  3. Let numNode be the second element of args.
  4. Let num be the result of Evaluate(numNode, scope).
  5. If num is not a number:
    1. Return null.
  6. If num is negative:
    1. Return null.
  7. Return result.
boost_validate(args)
  1. If the length of args is not 2:
    1. Report an error.

11.1.14global::lower()

The lower function returns lowercased string.

global_lower(args, scope)
  1. Let value be the result of Evaluate(arg, scope).
  2. If value is not null:
    1. Return lowercase form of value.
  3. Return null.
global_lower_validate(args)
  1. If the length of args is not 1:
    1. Report an error.

11.1.15global::upper()

The upper function returns uppercased string.

global_upper(args, scope)
  1. Let value be the result of Evaluate(arg, scope).
  2. If value is not null:
    1. Return uppercase form of value.
  3. Return null.
global_upper_validate(args)
  1. If the length of args is not 1:
    1. Report an error.

In addition to the functions mentioned above, constructors for extensions are global as well.

11.2Date/time namespace

The dateTime namespace contains functions to work with datetimes.

11.2.1dateTime::now()

The now function in the dateTime namespace returns the current point in time as a datetime.

dateTime_now(args, scope)
  1. Let result be a datetime representing the current point in time.
  2. Return result.
dateTime_now_validate(args)
  1. If the length of args is not 0:
    1. Report an error.

11.3Diff namespace

The diff namespace contains functionality for comparing objects.

11.3.1diff::changedAny()

The changedAny function in the diff namespace returns a boolean if any of the key paths matched by the selector are changed.

diff_changedAny(args, scope)
  1. Let lhs be the first element of args.
  2. Let rhs be the second element of args.
  3. Let selector be the third element of args.
  4. Let before be the result of Evaluate(lhs, scope).
  5. Let after be the result of Evaluate(rhs, scope).
  6. Let selectedKeyPaths be the result of EvaluateSelector(selector, before, scope).
  7. Let diffKeyPaths be the list of key paths that are different in before and after.
  8. If diffKeyPaths overlaps with selectedKeyPaths:
    1. Return true.
  9. Otherwise:
    1. Return false.
diff_changedAny_validate(args)
  1. If the length of args is not 3:
    1. Report an error.
  2. If the third element is not a Selector:
    1. Report an error.

11.3.2diff::changedOnly()

The changedOnly function in the diff namespace returns a boolean if given two nodes only the given key paths matched by the selector are changed.

diff_changedOnly(args, scope)
  1. Let lhs be the first element of args.
  2. Let rhs be the second element of args.
  3. Let selector be the third element of args.
  4. Let before be the result of Evaluate(lhs, scope).
  5. Let after be the result of Evaluate(rhs, scope).
  6. Let selectedKeyPaths be the result of EvaluateSelector(selector, before, scope).
  7. Let diffKeyPaths be the list of key paths that are different in before and after.
  8. If diffKeyPaths is a subset of selectedKeyPaths:
    1. Return true.
  9. Otherwise:
    1. Return false.
diff_changedOnly_validate(args)
  1. If the length of args is not 3:
    1. Report an error.
  2. If the third element is not a Selector:
    1. Report an error.

11.4Delta namespace

The delta namespace contains functions which are valid in delta mode.

11.4.1delta::changedAny

delta::changedAny is a variant of diff::changedAny which works on the before/after objects.

delta_changedAny(args, scope)
  1. Let before and after be the before/after objects of the query context to scope.
  2. Let selector by the first element of args.
  3. Let result be the result of diff_changedAny(before, after, selector).
  4. Return result.
delta_changedAny_validate(args, scope)
  1. If the mode of the query context of scope is not “delta”:
    1. Report an error.
  2. If the first element is not a Selector:
    1. Report an error.

11.4.2delta::changedOnly

delta::changedOnly is a variant of diff::changedOnly which works on the before/after objects.

delta_changedOnly(args, scope)
  1. Let before and after be the before/after objects of the query context to scope.
  2. Let selector by the first element of args.
  3. Let result be the result of diff_changedOnly(before, after, selector).
  4. Return result.
delta_changedOnly_validate(args, scope)
  1. If the mode of the query context of scope is not “delta”:
    1. Report an error.
  2. If the first element is not a Selector:
    1. Report an error.

11.4.3delta::operation()

The operation function returns the current operation ("create", "update", "delete") of a change in delta mode.

delta_operation(args, scope)
  1. Let before and after be the before/after objects of the query context to scope.
  2. If before is null:
    1. Return "create".
  3. If after is null:
    1. Return "delete".
  4. Return "update".
delta_operation_validate(args)
  1. If the length of args is not 0:
    1. Report an error.

11.5Array namespace

The array namespace contains functions to work with arrays.

11.5.1array::join()

The join function concatenates together the elements of an array into a single output string. Only primitive values supported by global::string() can be collected. Objects, arrays, etc. are considered composite values that cannot be joined.

array_join(args, scope)
  1. Let arrNode be the first element of args.
  2. Let sepNode be the second element of args.
  3. Let arr be the result of Evaluate(arrNode, scope).
  4. Let sep be the result of Evaluate(sepNode, scope).
  5. If arr is not an array:
    1. Return null.
  6. If sep is not a string:
    1. Return null.
  7. Let output be an empty string.
  8. For each element in arr:
    1. Let elem be the element.
    2. Let index be the index of the element.
    3. If index is greater than or equal to 1, append sep to output.
    4. Let str be the result of evaluating global::string(elem).
    5. If str is null:
      1. Return null.
    6. Otherwise:
      1. Append str to output.
  9. Return output.
array_join_validate(args)
  1. If the length of args is not 2:
    1. Report an error.

11.5.2array::compact()

The compact function filters null values from an array.

array_compact(args, scope)
  1. Let arrNode be the first element of args.
  2. Let arr be the result of Evaluate(arrNode, scope).
  3. If arr is not an array:
    1. Return null
  4. Let output be an empty array.
  5. For each element in arr:
    1. Let elem be the element
    2. If elem is not null:
      1. Append elem to output.
  6. Return output.
array_compact_validate(args)
  1. If the length of args is not 1:
    1. Report an error.

11.5.3array::unique()

The unique function filters duplicate values from an array.

Only values that can be compared for equality are compared for uniqueness. All other values are considered individually unique. For example, array::unique([[1], [1]]) should return [[1], [1]].

The algorithm below specifies a linear search, but since an implementation can choose to use hashing or a similar non-order-preserving data structure for efficiency, the order of the output cannot be guaranteed to be the same as the input.

array_unique(args, scope)
  1. Let arrNode be the first element of args.
  2. Let arr be the result of Evaluate(arrNode, scope).
  3. If arr is not an array:
    1. Return null.
  4. Let output be an empty array.
  5. For each element in arr:
    1. Let elem be the element
    2. Let found be false.
    3. If elem is comparable (see above):
      1. For each element in arr:
        1. Let b be the element.
        2. Set found be the result of Equal(elem, b)
        3. If found is true:
          1. Break loop
    4. If found is false:
      1. Add elem to output at any position.
  6. Return output.
array_unique_validate(args)
  1. If the length of args is not 1:
    1. Report an error.

11.5.4array::intersects()

The intersects function compares two arrays, returning true if they have any elements in common.

Only values that can be compared for equality are considered when determining whether there are common values.

array_intersects(args, scope)
  1. Let firstNode be the first element of args.
  2. Let first be the result of Evaluate(firstNode, scope).
  3. If first is not an array:
    1. Return null.
  4. Let secondNode be the first element of args.
  5. Let second be the result of Evaluate(secondNode, scope).
  6. If second is not an array:
    1. Return null.
  7. For each element in first:
    1. Let a be the element.
    2. For each element in second:
      1. Let b be the element.
      2. Set equal to be the result of Equal(a, b).
      3. If equal is true:
        1. Return true.
  8. Return false.
array_intersects_validate(args)
  1. If the length of args is not 2:
    1. Report an error.

11.6String namespace

The string namespace contains functions to work with strings.

11.6.1string::split()

The split function splits a string into multiple strings, given a separator string.

string_split(args, scope)
  1. Let strNode be the first element of args.
  2. Let sepNode be the second element of args.
  3. Let str be the result of Evaluate(strNode, scope).
  4. If str is not a string, return null.
  5. Let sep be the result of Evaluate(sepNode, scope).
  6. If sep is not a string, return null.
  7. Let output be an empty array.
  8. If sep is an empty string:
    1. Let output be each character of str, according to Unicode character splitting rules.
  9. Otherwise:
    1. Let output be each substring of str as separated by sep. An empty string is considered a substring, and will be included when sep is present at the beginning, the end, or consecutively of str. For example, the string ,a,b, when split by , will result in four substrings ['', 'a', 'b', ''].
  10. Return output.
string_split_validate(args)
  1. If the length of args is not 2:
    1. Report an error.

11.6.2string::startsWith()

The startsWith function evaluates whether a string starts with a given prefix.

string_startsWith(args, scope)
  1. Let strNode be the first element of args.
  2. Let prefixNode be the second element of args.
  3. Let str be the result of Evaluate(strNode, scope).
  4. If str is not a string, return null.
  5. Let prefix be the result of Evaluate(sepNode, scope).
  6. If prefix is not a string, return null.
  7. Let n be the length of prefix.
  8. If n is zero:
    1. Return true.
  9. If the first n characters of str equal prefix:
    1. Return true.
  10. Otherwise return false.
string_startsWith_validate(args)
  1. If the length of args is not 2:
    1. Report an error.

11.7Math namespace

The math namespace contains functions for performing mathematical operations.

11.7.1math::sum()

The sum function computes the sum of all numbers in an array. null values are ignored, but non-numbers cause the function to return null. If the array does not contain at least one numeric value, it returns 0.

math_sum(args, scope)
  1. Let arrNode be the first element of args.
  2. Let arr be the result of Evaluate(arrNode, scope).
  3. If arr is not an array, return null.
  4. Let n be zero.
  5. For each element elem in arr:
    1. If elem is null:
      1. Ignore it.
    2. If elem is not a number:
      1. Return null.
    3. Otherwise:
      1. Add elem to n.
  6. Return n.
math_sum_validate(args)
  1. If the length of args is not 1:
    1. Report an error.

11.7.2math::avg()

The avg function computes the arithmetic mean of all numbers in an array. null values are ignored, but non-numbers cause the function to return null. If the array does not contain at least one numeric value, it returns null.

math_avg(args, scope)
  1. Let arrNode be the first element of args.
  2. Let arr be the result of Evaluate(arrNode, scope).
  3. If arr is not an array, return null.
  4. Let n be zero.
  5. Let count be zero.
  6. For each element elem in arr:
    1. If elem is null:
      1. Ignore it.
    2. If elem is not a number:
      1. Return null.
    3. Otherwise:
      1. Increment count.
      2. Add elem to n.
  7. If count is zero:
    1. Return null.
  8. Return n divided by the count.
math_avg_validate(args)
  1. If the length of args is not 1:
    1. Report an error.

11.7.3math::min()

The min function finds the smallest numeric value in an array. null values are ignored, but non-numbers cause the function to return null. If the array does not contain at least one numeric value, it returns null.

math_min(args, scope)
  1. Let arrNode be the first element of args.
  2. Let arr be the result of Evaluate(arrNode, scope).
  3. If arr is not an array, return null.
  4. Let min be null.
  5. For each element elem in arr:
    1. If elem is null:
      1. Ignore it.
    2. If elem is not a number:
      1. Return null.
    3. Otherwise:
      1. If min is null or PartialCompare(elem, min) is Lower:
        1. Set min to elem.
  6. Return min.
math_min_validate(args)
  1. If the length of args is not 1:
    1. Report an error.

11.7.4math::max()

The max function finds the largest numeric value in an array. null values are ignored, but non-numbers cause the function to return null. If the array does not contain at least one numeric value, it returns null.

math_max(args, scope)
  1. Let arrNode be the first element of args.
  2. Let arr be the result of Evaluate(arrNode, scope).
  3. If arr is not an array, return null.
  4. Let max be null.
  5. For each element elem in arr:
    1. If elem is null:
      1. Ignore it.
    2. If elem is not a number:
      1. Return null.
    3. Otherwise:
      1. If max is null or PartialCompare(elem, max) is Greater:
        1. Set max to elem.
  6. Return max.
math_max_validate(args)
  1. If the length of args is not 1:
    1. Report an error.

12Pipe functions

Pipe functions provide additional functionality to GROQ queries. They are invoked through a Pipe function call expression. They differ from regular functions in that they always accept an array as input and returns another array (or null). As such, the syntax is optimized for chaining (the array it works on comes on the left-hand side instead of being an argument):

Example № 23*[_type == "person"] | order(name) | {age}
Note that function arguments are not evaluated eagerly, and it’s up to the function to decide which scope the arguments are evaluated in. All definitions below take an array of nodes.

An implementation may provide additional pipe functions, but should be aware that this can cause problems when interoperating with future versions of GROQ.

12.1global::order()

The order function sorts an array based on arbitrary expressions.

order(base, args, scope)
  1. Let cmp be a function which takes two arguments and returns either Less, Equal or Greater.
  2. Define cmp(left, right) as follows:
    1. Let leftScope be the result of NewNestedScope(left, scope).
    2. Let rightScope be the result of NewNestedScope(right, scope).
    3. For each argNode of args:
      1. Let direction be Normal.
      2. Let valueNode be argNode.
      3. If valueNode is an Asc operator: * Set valueNode to be the Expression of the Asc operator.
      4. Else if valueNode is a Desc operator: * Set direction to Reverse.
        1. Set valueNode to be the Expression of the Desc operator.
      5. Let leftValue be the result of Evaluate(valueNode, leftScope).
      6. Let rightValue be the result of Evaluate(valueNode, rightScope).
      7. Let order be the result of TotalCompare(leftValue, rightValue).
      8. If direction is Reverse and order is Less: * Set order to Greater.
      9. Else if direction is Reverse and order is Greater: * Set order to Less.
      10. If order is not Equal: * Return order.
    4. Return Equal.
  3. Return a sorted array using cmp as the comparator function.
order_validate(args)
  1. If the length of args is 0:
    1. Report an error.

12.2global::score()

The score function assigns a score to an array of results, based on one or more scoring expressions. The score function may only be used as a pipe function.

Example № 24*[_type == "listing"] | score(body match "jacuzzi")

In this query, anything where body match "jacuzzi" returns true will be scored higher than other results. Multiple expressions can be used:

Example № 25*[_type == "listing"] | score(body match "jacuzzi", bedrooms > 2, available && !inContract)

When multiple expressions are provided, the scores are merged into a single score for each result (see score evaluation)

Only predicate expressions — that is, expressions that evaluate to a single boolean value or to null — may be used, including boost(). However, an implementation can put further constraints on which expressions are permitted as a score expression for optimization purposes.

Each score is assigned to the result as the new attribute _score, set to a positive number.

Scoring is additive. That is * | score(a == 1) | score(b == 2) is equivalent to * | score(a == 1, b == 2).

score(base, args, scope)
  1. Let baseNode be the Expression.
  2. Let base be the result of Evaluate(baseNode, scope).
  3. If base is an array:
    1. Let result be an empty Array.
    2. For each element of base:
      1. If element is an object:
        1. Let elementScope be the result of NewNestedScope(element, scope).
        2. Let newElement be a new empty Object.
        3. Add the attributes from element to it.
        4. If element already has a _score:
          1. Let scoreSum be the current value of _score.
          2. Otherwise let scoreSum be 1.0.
        5. For each predicateNode of args:
          1. Let scoreValue be the result of EvaluateScore(predicateNode, elementScope).
          2. Add scoreValue to scoreSum.
        6. Add the attribute _score set to scoreSum.
        7. Add newElement to result.
      2. Otherwise add element to result.
    3. Return result sorted by the score, in descending order.
  4. Return null.
EvaluateScore(expr, scope)
  1. Let evaluator be the score evaluator of expr.
  2. Return the result of evaluator(scope).
score_validate(args)
  1. If the length of args is 0:
    1. Report an error.

13Vendor functions

An implementation is free to introduce additional functions than what is presented in this specification, but this is problematic if a function with the same name is introduced in a future version. The following section defines optional vendor functions which are guaranteed to never be a regular function in a future specification. There’s also a short description of each vendor function so different implementations can attempt to be compatible with each other. The description is intentionally brief and it’s up to the vendor to define it completely.

13.1global::identity()

The identity function should accept zero arguments and return a string which represents the identity of the client executing the query.

13.2global::path()

The path function should accept a single argument and return a path object.

14Extensions

Extensions are the capabilities which extend GROQ queries beyond basic Spec. These capabilities can include function namespaces, functions and operators. However, extensions can not introduce a new syntax.

14.1Portable Text Extension

Functions available in Portable text extension are grouped under pt namespace except for the constructor which is global.

14.1.1pt type

PT type represents an object following portable text spec.

14.1.2global::pt()

This function takes in an object or an array of objects, and returns a PT value.

global_pt(args, scope)
  1. Let baseNode be the first element of args.
  2. Let base be the result of Evaluate(baseNode, scope).
  3. If base is an object:
    1. Try to parse it as Portable Text Block:
    2. If base is a valid Portable Text Block:
      1. Return base.
  4. If base is an array of objects:
    1. Try to parse it as an array of Portable Text blocks:
      1. If all elements in base array are valid Portable Text blocks:
        1. Return base.
  5. Otherwise:
    1. Return null.
global_pt_validate(args)
  1. If the length of args is not 1:
    1. Report an error.

14.1.3pt::text()

This function takes in a PT value and returns a string versions of text. PT value which consists of more than one Portable text block has blocks appended with double newline character (\n\n) in the string version.

pt_text(args, scope)
  1. Let baseNode be the first element of args.
  2. Let base be the result of Evaluate(baseNode, scope).
  3. If base is an object:
    1. Try to parse it as Portable Text Block:
    2. If baseis a valid Portable Text Block:
      1. Return string version of text in base.
  4. If base is an array of objects:
    1. Try to parse it as an array of Portable Text blocks:
    2. If all elements in base array are valid Portable Text blocks:
      1. Return string version of text in base.
  5. Otherwise:
    1. Return null.
pt_text_validate(args)
  1. If the length of args is not 1:
    1. Report an error.

14.2Geography Extension

Functions available in Geography extension are grouped under geo namespace except for the constructor which is global.

14.2.1geo type

The geo type represents a geography and can contain points, lines, and polygons which can be expressed with a single latitude/longitude coordinate, or as a GeoJSON object. Concretely, an object is coerced to the geo type if:

  1. If the object is coerced to a geographic point, that is it has a key lat for latitude and a key lng or lon for longitude (but not both).
  2. If the object has GeoJSON representation.

Geo type supports following GeoJSON Geometry Objects:

  1. Position
  2. Point
  3. MultiPoint
  4. LineString
  5. MultiLineString
  6. Polygon
  7. MultiPolygon
  8. GeometryCollection

And, it does not support:

  1. GeoJSON Object Feature and FeatureCollection.
  2. Arrays of geographic values. Instead, one of the GeoJSON Multi types should be used.

14.2.2global::geo()

This function is a constructor for geographic value. It takes an object or another geo value, returning a geo value.

global_geo(args, scope)
  1. Let baseNode be the first element of args.
  2. Let base be the result of Evaluate(baseNode, scope).
  3. If base is an object:
    1. Try to parse it as Geo Point and GeoJSON:
    2. If base is a valid geo value:
      1. Return base.
  4. If base is a geo value:
    1. Return base.
  5. Otherwise:
    1. Return null.
global_geo_validate(args)
  1. If the length of args is not 1:
    1. Report an error.

14.2.3geo::latLng()

Takes latitude and longitude as arguments and returns a Geo Point.

geo_latLng(args, scope)
  1. Let latNode be the first element of args.
  2. Let lngNode be the second element of args.
  3. Let lat be the result of Evaluate(latNode, scope).
  4. Let lng be the result of Evaluate(lngNode, scope).
  5. If lat or lng is not a number:
    1. Return null.
  6. If lat is not in the range of -90 to 90:
    1. Return null.
  7. If lng is not in the range of -180 to 180:
    1. Return null.
  8. Otherwise:
    1. Return a GeoJSON Point with lat and lng as coordinates, in lng, lat order.
geo_latLng_validate(args)
  1. If the length of args is not 2:
    1. Report an error.

14.2.4geo::contains()

Returns true if first geo argument completely contains the second one, using a planar (non-spherical) coordinate system. Both geo argument can be any geo value. A geo value is considered contained if all its points are within the boundaries of the first geo value. For MultiPolygon, it’s sufficient that only one of the polygons contains the first geo value.

geo_contains(args, scope)
  1. Let firstNode be the first element of args.
  2. Let secondNode be the second element of args.
  3. Let first be the result of Evaluate(firstNode, scope).
  4. Let second be the result of Evaluate(secondNode, scope).
  5. If first or second is a not a geo value:
    1. Return null.
  6. If first completely contains second:
    1. Return true.
  7. Otherwise:
    1. Return false.
geo_contains_validate(args)
  1. If the length of args is not 2:
    1. Report an error.

14.2.5geo::intersects()

This function takes two geo values, and returns true if they intersect in a planar (non-spherical) coordinate system. The arguments can be any geo values. A geo value intersects with another if it shares any geometric points with the second value; for example, a line crossing a polygon.

geo_intersects(args, scope)
  1. Let firstNode be the first element of args.
  2. Let secondNode be the second element of args.
  3. Let first be the result of Evaluate(firstNode, scope).
  4. Let second be the result of Evaluate(secondNode, scope).
  5. If first or second is a not a geo value:
    1. Return null.
  6. If first intersects second:
    1. Return true.
  7. Otherwise:
    1. Return false.
geo_intersects_validate(args)
  1. If the length of args is not 2:
    1. Report an error.

14.2.6geo::distance()

This functions accepts two geo values, which must be point values, and returns the distance in meters. While exact algorithm is implementation-defined — for example, it may use the Haversine formula — it should use as close an approximation to a real Earth distance as possible.

geo_distance(args, scope)
  1. Let firstNode be the first element of args.
  2. Let secondNode be the second element of args.
  3. Let first be the result of Evaluate(firstNode, scope).
  4. Let second be the result of Evaluate(secondNode, scope).
  5. If first or second is a not a geo value:
    1. Return null.
  6. If first or second is a not a Geo Point or GeoJSON Point:
    1. Return null.
  7. Let distance be the geographic distance between first and second:
    1. Return distance.
  8. Otherwise:
    1. Return null.
geo_distance_validate(args)
  1. If the length of args is not 2:
    1. Report an error.

§Index

  1. And
  2. Array
  3. array_compact
  4. array_compact_validate
  5. array_intersects
  6. array_intersects_validate
  7. array_join
  8. array_join_validate
  9. array_unique
  10. array_unique_validate
  11. ArrayElement
  12. ArrayElements
  13. ArrayPostfix
  14. Asc
  15. AttributeAccess
  16. BasicTraversalArray
  17. BasicTraversalPlain
  18. Boolean
  19. boost
  20. boost_validate
  21. Comment
  22. CommentChar
  23. Comparison
  24. ComparisonOperator
  25. CompoundExpression
  26. ConstantEvaluate
  27. dateTime_now
  28. dateTime_now_validate
  29. Decimal
  30. delta_changedAny
  31. delta_changedAny_validate
  32. delta_changedOnly
  33. delta_changedOnly_validate
  34. delta_operation
  35. delta_operation_validate
  36. Dereference
  37. Desc
  38. DetermineName
  39. diff_changedAny
  40. diff_changedAny_validate
  41. diff_changedOnly
  42. diff_changedOnly_validate
  43. Digit
  44. DisambiguateSquareBracketTraversal
  45. DoubleStringCharacter
  46. ElementAccess
  47. Equal
  48. Equality
  49. EqualityOperator
  50. EscapeSequence
  51. Evaluate
  52. EvaluateAnd
  53. EvaluateArray
  54. EvaluateArrayPostfix
  55. EvaluateAttributeAccess
  56. EvaluateComparison
  57. EvaluateDereference
  58. EvaluateElementAccess
  59. EvaluateEquality
  60. EvaluateEverything
  61. EvaluateFilter
  62. EvaluateFuncCall
  63. EvaluateIn
  64. EvaluateMatch
  65. EvaluateMinus
  66. EvaluateNot
  67. EvaluateObject
  68. EvaluateOr
  69. EvaluatePair
  70. EvaluateParent
  71. EvaluateParenthesis
  72. EvaluatePercent
  73. EvaluatePipeFuncCall
  74. EvaluatePlus
  75. EvaluateProjection
  76. EvaluateRange
  77. EvaluateScore
  78. EvaluateSelector
  79. EvaluateSlash
  80. EvaluateSlice
  81. EvaluateStar
  82. EvaluateStarStar
  83. EvaluateThis
  84. EvaluateThisAttribute
  85. EvaluateTraversalExpression
  86. EvaluateTraversalFlatMap
  87. EvaluateTraversalInnerMap
  88. EvaluateTraversalJoin
  89. EvaluateTraversalMap
  90. EvaluateUnaryMinus
  91. EvaluateUnaryPlus
  92. Everything
  93. ExclusiveRange
  94. ExecuteQuery
  95. ExponentMarker
  96. Expression
  97. Filter
  98. Fractional
  99. FuncCall
  100. FuncCallArgs
  101. FuncIdentifier
  102. FuncNamespace
  103. geo_contains
  104. geo_contains_validate
  105. geo_distance
  106. geo_distance_validate
  107. geo_intersects
  108. geo_intersects_validate
  109. geo_latLng
  110. geo_latLng_validate
  111. global_after
  112. global_after_validate
  113. global_before
  114. global_before_validate
  115. global_coalesce
  116. global_count
  117. global_count_validate
  118. global_dateTime
  119. global_dateTime_validate
  120. global_defined
  121. global_defined_validate
  122. global_geo
  123. global_geo_validate
  124. global_length
  125. global_length_validate
  126. global_lower
  127. global_lower_validate
  128. global_now
  129. global_now_validate
  130. global_pt
  131. global_pt_validate
  132. global_references
  133. global_references_validate
  134. global_round
  135. global_round_validate
  136. global_select
  137. global_select_validate
  138. global_string
  139. global_string_validate
  140. global_upper
  141. global_upper_validate
  142. HasReferenceTo
  143. HexDigit
  144. HexLetter
  145. Identifier
  146. In
  147. InclusiveRange
  148. Integer
  149. Literal
  150. Match
  151. MatchAnalyzePattern
  152. MatchTokenize
  153. math_avg
  154. math_avg_validate
  155. math_max
  156. math_max_validate
  157. math_min
  158. math_min_validate
  159. math_sum
  160. math_sum_validate
  161. Minus
  162. NewNestedScope
  163. NewRootScope
  164. Not
  165. Null
  166. Number
  167. Object
  168. ObjectAttribute
  169. ObjectAttributes
  170. OperatorCall
  171. Or
  172. order
  173. order_validate
  174. Pair
  175. Parent
  176. Parenthesis
  177. PartialCompare
  178. Percent
  179. PipeFuncCall
  180. Plus
  181. Projection
  182. pt_text
  183. pt_text_validate
  184. Range
  185. ScientificNotation
  186. score
  187. score_validate
  188. Selector
  189. SelectorGroup
  190. SelectorTuple
  191. SelectorTuplePart
  192. Sign
  193. SimpleExpression
  194. SingleEscapeSequence
  195. SingleStringCharacter
  196. Slash
  197. Slice
  198. SourceCharacter
  199. SquareBracketTraversal
  200. Star
  201. StarStar
  202. String
  203. string_split
  204. string_split_validate
  205. string_startsWith
  206. string_startsWith_validate
  207. This
  208. ThisAttribute
  209. TotalCompare
  210. Traversal
  211. TraversalArray
  212. TraversalArraySource
  213. TraversalArrayTarget
  214. TraversalExpression
  215. TraversalPlain
  216. TypeOrder
  217. UnaryMinus
  218. UnaryPlus
  219. UnicodeEscapeSequence
  220. Validate
  221. ValidateAsc
  222. ValidateDesc
  223. ValidateElementAccess
  224. ValidateFuncCall
  225. ValidateObject
  226. ValidateObjectAttribute
  227. ValidatePipeFuncCall
  228. ValidateSlice
  229. WhiteSpace
  1. 1Overview
  2. 2Syntax
    1. 2.1JSON Superset
    2. 2.2White Space
    3. 2.3Comments
    4. 2.4Identifier
    5. 2.5Digits
    6. 2.6Expression
    7. 2.7Selector
  3. 3Execution
    1. 3.1Overview
    2. 3.2Mode
    3. 3.3Query context
    4. 3.4Scope
    5. 3.5Expression validation
    6. 3.6Expression evaluation
    7. 3.7Constant expression evaluation
    8. 3.8Score evaluation
    9. 3.9Selector evaluation
    10. 3.10Traversal execution
      1. 3.10.1Combining traversal
      2. 3.10.2Plain traversal
      3. 3.10.3Array traversals
      4. 3.10.4Array source traversals
      5. 3.10.5Array target traversals
    11. 3.11Query execution
  4. 4Data types
    1. 4.1Null
    2. 4.2Boolean
    3. 4.3Number
    4. 4.4String
    5. 4.5Array
    6. 4.6Object
    7. 4.7Pair
    8. 4.8Range
    9. 4.9Datetime
  5. 5Equality and comparison
    1. 5.1Equality
    2. 5.2Partial comparison
    3. 5.3Total comparison
  6. 6Simple expressions
    1. 6.1This expression
    2. 6.2This attribute expression
    3. 6.3Everything expression
    4. 6.4Parent expression
    5. 6.5Function call expression
  7. 7Compound expressions
    1. 7.1Parenthesis expression
    2. 7.2Traversal expression
    3. 7.3Pipe function call expression
  8. 8Traversal operators
    1. 8.1Attribute access traversal
    2. 8.2Element access traversal
    3. 8.3Slice traversal
    4. 8.4Filter traversal
    5. 8.5Array postfix traversal
    6. 8.6Projection traversal
    7. 8.7Dereference traversal
    8. 8.8Disambiguating square bracket traversal
  9. 9Operators
    1. 9.1And operator
    2. 9.2Or operator
    3. 9.3Not operator
    4. 9.4Equality operators
    5. 9.5Comparison operators
    6. 9.6In operator
    7. 9.7Match operator
    8. 9.8Asc operator
    9. 9.9Desc operator
    10. 9.10Unary plus operator
    11. 9.11Unary minus operator
    12. 9.12Binary plus operator
    13. 9.13Binary minus operator
    14. 9.14Binary star operator
    15. 9.15Binary slash operator
    16. 9.16Binary percent operator
    17. 9.17Binary double star operator
  10. 10Precedence and associativity
  11. 11Functions
    1. 11.1Global namespace
      1. 11.1.1global::after()
      2. 11.1.2global::before()
      3. 11.1.3global::coalesce()
      4. 11.1.4global::count()
      5. 11.1.5global::dateTime()
      6. 11.1.6global::defined()
      7. 11.1.7global::length()
      8. 11.1.8global::now()
      9. 11.1.9global::references()
      10. 11.1.10global::round()
      11. 11.1.11global::select()
      12. 11.1.12global::string()
      13. 11.1.13global::boost()
      14. 11.1.14global::lower()
      15. 11.1.15global::upper()
    2. 11.2Date/time namespace
      1. 11.2.1dateTime::now()
    3. 11.3Diff namespace
      1. 11.3.1diff::changedAny()
      2. 11.3.2diff::changedOnly()
    4. 11.4Delta namespace
      1. 11.4.1delta::changedAny
      2. 11.4.2delta::changedOnly
      3. 11.4.3delta::operation()
    5. 11.5Array namespace
      1. 11.5.1array::join()
      2. 11.5.2array::compact()
      3. 11.5.3array::unique()
      4. 11.5.4array::intersects()
    6. 11.6String namespace
      1. 11.6.1string::split()
      2. 11.6.2string::startsWith()
    7. 11.7Math namespace
      1. 11.7.1math::sum()
      2. 11.7.2math::avg()
      3. 11.7.3math::min()
      4. 11.7.4math::max()
  12. 12Pipe functions
    1. 12.1global::order()
    2. 12.2global::score()
  13. 13Vendor functions
    1. 13.1global::identity()
    2. 13.2global::path()
  14. 14Extensions
    1. 14.1Portable Text Extension
      1. 14.1.1pt type
      2. 14.1.2global::pt()
      3. 14.1.3pt::text()
    2. 14.2Geography Extension
      1. 14.2.1geo type
      2. 14.2.2global::geo()
      3. 14.2.3geo::latLng()
      4. 14.2.4geo::contains()
      5. 14.2.5geo::intersects()
      6. 14.2.6geo::distance()
  15. §Index