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 and Magnus Holm.

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:

*[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:

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

Comments cannot start inside a string literal.

{ 
  "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.

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.

*[_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.

*[_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.2Query context

A query context consists of:

  • the dataset
  • parameter values (map from string to value)

3.3Scope

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.4Expression 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 specifiction, 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.5Expression 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.6Score 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:

* | 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.7Query 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 refering 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 preceeded by ... which causes it to be flattened into the array.

EvaluateArray(scope)
  1. Let result be a new empty array.
  2. For each ArrayElement:
    1. Let elementNode be the Expression of the ArrayElement.
    2. Let element be the result of Evaluate(elementNode, scope).
    3. If the ArrayElement contains ...:
      1. If element is an array:
        1. Concatenate element to result.
    4. Otherwise:
      1. Append element to result.
  3. 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:

*[_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:

// 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 constains an Expression:
        1. Let baseNode be the Expression.
      2. Let base be the result of Evaluate(baseNode, scope).
    2. Otherwise:
      1. Let base be the this value of scope.
    3. For each name and value of base:
      1. Set the attribute name to value in result.
    4. 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 Projection, ElementAccess, Slice, or Filter:
    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-dependant 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 Evalaute(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:
      1. Return Greater.
    3. If a is shorter than b:
      1. Return Less.
    4. If a is longer than b:
      1. Return Greater.
    5. 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:
  7. Return result.

6Simple expressions

6.1This expression

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

*[_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.

*[_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.

*[_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.

// 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.

*{"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.

(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.2Attribute access expression

An attribute access expression returns an attribute of an object.

person.name
      ~~~~~

person["Full Name"]
      ~~~~~~~~~~~~~
Note This expression is syntactially a subset of a filter expression.
EvaluateAttributeAccess(scope)
  1. Let baseNode be the Expression.
  2. Let base be the result of Evaluate(baseNode, scope).
  3. If base is not an object, return null.
  4. Let name be the string value of String or Identifier.
  5. If base does not contain an attribute name, return null.
  6. Return the value of the attribute name in base.

7.3Element access expression

An element access expression 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 This expression is syntactially a subset of a filter expression.
EvaluateElementAccess(scope)
  1. Let baseNode be the Expression.
  2. Let base be the result of Evaluate(baseNode, scope).
  3. If base is not an array, return null.
  4. Let idx be the number value of Integer.
  5. If idx is negative, add the length of base to idx.
  6. If idx is still negative, return null.
  7. If idx is equal to or greater than the length of base, return null.
  8. Return the value stored at position idx in base.

7.4Slice expression

A slice expression returns a slice of an array.

people[0..10]
      ~~~~~~~
Note This expression is syntactically a subset of a filter expression.
EvaluateSlice(scope)
  1. Let baseNode be the Expression.
  2. Let base be the result of Evaluate(baseNode, scope).
  3. If base is not an array, return null.
  4. Process the left index:
    1. Let leftNode be the left value of the Range.
    2. Let left be the result of Evaluate(leftNode, scope).
    3. If left is not a number, return null.
    4. If left is negative, add the length of base to left.
    5. Clamp left between 0 and (the length of base minus 1).
  5. Process the right index:
    1. Let rightNode be the right value of the Range.
    2. Let right be the result of Evaluate(rightNode, scope).
    3. If right is not a number, return null.
    4. If right is negative, add the length of base to right.
    5. If the Range is exclusive, subtract one from right.
    6. Clamp right between 0 and (the length of base minus 1).
  6. Let result be an array containing the elements of base from position left up to and including position right.
  7. Return result.

7.5Filter expression

A filter expression filters an array using another expression.

*[_type == "person"]
 ~~~~~~~~~~~~~~~~~~~
Note If the second Expression is a string/integer/range literal, this is parsed as an attribute access/element access/slice expression instead.
EvaluateFilter(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, return base.
  4. Let filterNode be the second Expression.
  5. Let result be a new empty array.
  6. 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.
  7. Return result.

7.6Projection expression

A projection expression iterates over an array and creates new objects for each element.

*[_type == "person"]{name, "isLegal": age >= 18}
                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
EvaluateProjection(scope)
  1. Let baseNode be the Expression.
  2. Let base be the result of Evaluate(baseNode, scope).
  3. Let objNode be the Object.
  4. If base is not an array:
    1. Let elementScope be the result of NewNestedScope(base, scope).
    2. Let result be the result of Evaluate(objNode, elementScope).
  5. Otherwise:
    1. Let result be a new empty array.
    2. For each element value in base:
      1. Let elementScope be the result of NewNestedScope(value, scope).
      2. Let newValue be the result of Evaluate(objNode, elementScope).
      3. Append newValue to result.
  6. Return result.

7.7Pipe 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 compund expressions. See the “Pipe functions” for available functions.

*[_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).

8Operators

8.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.

8.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.

8.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.

8.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.

8.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.

8.6In operator

EvaluateIn(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 right is an array:
    1. For each value in right:
      1. If Equal(left, value) is true:
        1. Return true.
    2. Return false.
  6. If right is a range:
    1. Let lower be the start value of right.
    2. Let upper be the end value of right.
    3. Let leftCmp be the result of PartialCompare(left, lower).
    4. Let rightCmp be the result of PartialCompare(left, upper).
    5. If leftCmp or rightCmp is null:
      1. Return null.
    6. If leftCmp is Less:
      1. Return false.
    7. If rightCmp is Greater:
      1. Return false.
    8. If the right range is exclusive and rightCmp is Equal:
      1. Return false.
    9. Return true.
  7. Return null.

8.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:
      1. 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.

8.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.

8.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.

8.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.

8.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.

8.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.

8.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.

8.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.

8.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.

8.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.

8.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.

8.18Dereference operator

EvaluateDereference(scope)
  1. Let valueNode be the Expression.
  2. Let value be the result of Evaluate(valueNode, scope).
  3. If value is not an object:
    1. Return null.
  4. If value does not have an attribute _ref:
    1. Return null.
  5. Let ref be the value of the attribute _ref in value.
  6. If ref is not a string:
    1. Return null.
  7. Let dataset be the dataset of the query context of scope.
  8. If dataset is not an array:
    1. Return null.
  9. Let result be null.
  10. 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.
    3. Stop the loop.
  11. If the dereference expression contains a String:
    1. Let name be the string value of the String.
    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.
  12. Return result.

9Precedence 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:

10Functions

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 interopting with future versions of GROQ.

11Namespaces

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::coalesce()

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

global::coalesce(args, scope):

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

11.1.2global::count()

The count function returns the length of an array.

global::count(args, scope):

  • Let baseNode be the first element of args.
  • Let base be the result of Evaluate(baseNode, scope).
  • If base is an array:
    • Return the length of base.
  • Otherwise:
    • Return null.

global::countValidate(args):

  • If the length of args is not 1:
    • Report an error.

11.1.3global::dateTime()

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

global::dateTime(args, scope):

  • Let baseNode be the first element of args.
  • Let base be the result of Evaluate(baseNode, scope).
  • If base is a string:
    • Try to parse base as a datetime using the RFC 3339 timestamp format.
    • If the input is a valid datetime:
      • Return the datetime.
  • If base is a datetime value:
    • Return base.
  • Return null.

global::dateTimeValidate(args):

  • If the length of args is not 1:
    • Report an error.

11.1.4global::defined()

The defined function checks if the argument is not null.

global::defined(args, scope):

  • Let baseNode be the first element of args.
  • Let base be the result of Evaluate(baseNode, scope).
  • If base is null:
    • Return false.
  • Otherwise:
    • Return true.

global::definedValidate(args):

  • If the length of args is not 1:
    • Report an error.

11.1.5global::length()

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

global::length(args, scope):

  • Let baseNode be the first element of args.
  • Let base be the result of Evaluate(baseNode, scope).
  • If base is a string:
    • Return the length of base.
  • If base is an array:
    • Return the length of base.
  • Return null.

global::lengthValidate(args):

  • If the length of args is not 1:
    • Report an error.

11.1.6global::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):

  • Let pathSet be an empty array.
  • For each arg of args:
    • Let path be the result of Evaluate(arg, scope).
    • If path is a string:
      • Append path to pathSet.
    • If path is an array:
      • Concatenate all strings of path to pathSet.
  • If pathSet is empty:
    • Return false.
  • Let base be the this value of scope.
  • Return the result of HasReferenceTo(base, pathSet).

global::HasReferenceTo(base, pathSet):

  • If base is an array:
    • For each value in base:
      • Let result be the result of HasReferenceTo(value, pathSet).
      • If result is true:
        • Return true.
    • Return false.
  • If base is an object:
    • If base has an attribute _ref:
      • Let ref be the value of the attribute _ref in base.
      • If ref exists in pathSet:
        • Return true.
      • Otherwise:
        • Return false.
    • For each key and value in base:
      • Let result be the result of HasReferenceTo(value, pathSet).
      • If result is true:
        • Return true.
  • Return false.

global::referencesValidate(args):

  • If the length of args is 0:
    • Report an error.

11.1.7global::round()

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

global::round(args, scope):

  • Let numNode be the first element of args.
  • Let num be the result of Evaluate(numNode, scope).
  • If num is not a number:
    • Return null.
  • If the length of args is 2:
    • Let precNode be the second element of args.
    • Let prec be the result of Evaluate(precNode, scope).
    • If prec is not a number:
      • Return null.
  • Otherwise:
    • Let prec be 0.
  • Return num rounded to prec number of digits after the decimal point.

global::roundValidate(args):

  • If the length of args is less than 1 or greater than 2:
    • Report an error.

11.1.8global::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):

  • For each arg in args:
    • If arg is a Pair:
      • Let condNode be the first Expression of the Pair.
      • Let resultNode be the second Expression of the Pair.
      • Let cond be the result of Evaluate(condNode, scope).
      • If cond is true:
        • Return the result of Evaluate(resultNode, scope).
    • Otherwise:
      • Return the result of Evaluate(arg, scope).

global::selectValidate(args):

  • Let seenDefault be false.
  • For each arg in args:
    • If seenDefault is true:
      • Report an error.
    • If arg is not a Pair:
      • Set seenDefault to true.

11.1.9global::string()

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

global::string(args, scope):

  • Let node be the first element of args.
  • Let val be the result of Evaluate(node, scope).
  • If val is true:
    • Return the string "true"
  • If val is false:
    • Return the string "false"
  • If val is a string:
    • Return val.
  • If val is a number:
    • Return a string representation of the number.
  • If val is a datetime:
    • Return the datetime in the RFC 3339 timestamp format with a Z suffix.
  • Otherwise:
    • Return null.

global::stringValidate(args):

  • If the length of args is not 1:
    • Report an error.

11.1.10global::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().

* | 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.
boostValidate(args)
  1. If the length of args is not 2:
    1. Report an error.

11.1.11global::lower()

The lower function returns lowercased string.

global::lower(args, scope):

  • Let value be the result of Evaluate(arg, scope).
  • If value is not null:
    • Return lowercase form of value.
  • Return null.

global::lowerValidate(args):

  • If the length of args is not 1:
    • Report an error.

11.1.12global::upper()

The upper function returns uppercased string.

global::upper(args, scope):

  • Let value be the result of Evaluate(arg, scope).
  • If value is not null:
    • Return uppercase form of value.
  • Return null.

global::upperValidate(args):

  • If the length of args is not 1:
    • Report an error.

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

12Pipe functions

Pipe functions provide additional functionalty 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):

*[_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 interopting 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.
    4. Let valueNode be argNode.
      1. If valueNode is an Asc operator:
        1. Set valueNode to be the Expression of the Asc operator.
      2. Else if valueNode is a Desc operator:
        1. Set direction to Reverse.
      3. Set valueNode to be the Expression of the Desc operator.
      4. Let leftValue be the result of Evaluate(valueNode, leftScope).
      5. Let rightValue be the result of Evaluate(valueNode, rightScope).
      6. Let order be the result of TotalCompare(leftValue, rightValue).
      7. If direction is Reverse and order is Less:
        1. Set order to Greater.
      8. Else if direction is Reverse and order is Greater:
        1. Set order to Less.
      9. If order is not Equal:
        1. Return order.
    5. Return Equal.
  3. Return a sorted array using cmp as the comparator function.
orderValidate(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.

*[_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:

*[_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).
scoreValidate(args)
  1. If the length of args is 0:
  2. 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 specfication. There’s also a short description of each vendor function so different implementations can attempt to be compatible with each other. The description is intentially 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):

  • Let baseNode be the first element of args.
  • Let base be the result of Evaluate(baseNode, scope).
  • If base is an object:
    • Try to parse it as Portable Text Block:
    • If base is a valid Portable Text Block:
      • Return base.
  • If base is an array of objects:
    • Try to parse it as an array of Portable Text blocks:
      • If all elements in base array are valid Portable Text blocks:
        • Return base.
  • Otherwise:
    • Return null.

global::ptValidate(args):

  • If the length of args is not 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):

  • Let baseNode be the first element of args.
  • Let base be the result of Evaluate(baseNode, scope).
  • If base is an object:
    • Try to parse it as Portable Text Block:
    • If baseis a valid Portable Text Block:
      • Return string version of text in base.
  • If base is an array of objects:
    • Try to parse it as an array of Portable Text blocks:
    • If all elements in base array are valid Portable Text blocks:
      • Return string version of text in base.
  • Otherwise:
    • Return null.

pt::textValidate(args):

  • If the length of args is not 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):

  • Let baseNode be the first element of args.
  • Let base be the result of Evaluate(baseNode, scope).
  • If base is an object:
    • Try to parse it as Geo Point and GeoJSON:
    • If base is a valid geo value:
      • Return base.
  • If base is a geo value:
    • Return base.
  • Otherwise:
    • Return null.

global::geoValidate(args):

  • If the length of args is not 1:
    • Report an error.

14.2.3geo::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):

  • Let firstNode be the first element of args.
  • Let secondNode be the second element of args.
  • Let first be the result of Evaluate(firstNode, scope).
  • Let second be the result of Evaluate(secondNode, scope).
  • If first or second is a not a geo value:
    • Return null.
  • If first completely contains second:
    • Return true.
  • Otherwise:
    • Return false.

geo::containsValidate(args):

  • If the length of args is not 2:
    • Report an error.

14.2.4geo::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):

  • Let firstNode be the first element of args.
  • Let secondNode be the second element of args.
  • Let first be the result of Evaluate(firstNode, scope).
  • Let second be the result of Evaluate(secondNode, scope).
  • If first or second is a not a geo value:
    • Return null.
  • If first intersects second:
    • Return true.
  • Otherwise:
    • Return false.

geo::intersectsValidate(args):

  • If the length of args is not 2:
    • Report an error.

14.2.5geo::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):

  • Let firstNode be the first element of args.
  • Let secondNode be the second element of args.
  • Let first be the result of Evaluate(firstNode, scope).
  • Let second be the result of Evaluate(secondNode, scope).
  • If first or second is a not a geo value:
    • Return null.
  • If first or second is a not a Geo Point or GeoJSON Point:
    • Return null.
  • Let distance be the geographic distance between first and second:
    • Return distance.
  • Otherwise:
    • Return null.

geo::distanceValidate(args):

  • If the length of args is not 2:
  • Report an error.

§Index

  1. And
  2. Array
  3. ArrayElement
  4. ArrayElements
  5. Asc
  6. AttributeAccess
  7. Boolean
  8. Comment
  9. CommentChar
  10. Comparison
  11. ComparisonOperator
  12. CompoundExpression
  13. Decimal
  14. Dereference
  15. Desc
  16. DetermineName
  17. Digit
  18. DoubleStringCharacter
  19. ElementAccess
  20. Equal
  21. Equality
  22. EqualityOperator
  23. EscapeSequence
  24. Evaluate
  25. EvaluateAnd
  26. EvaluateArray
  27. EvaluateAttributeAccess
  28. EvaluateComparison
  29. EvaluateDereference
  30. EvaluateElementAccess
  31. EvaluateEquality
  32. EvaluateEverything
  33. EvaluateFilter
  34. EvaluateFuncCall
  35. EvaluateIn
  36. EvaluateMatch
  37. EvaluateMinus
  38. EvaluateNot
  39. EvaluateObject
  40. EvaluateOr
  41. EvaluatePair
  42. EvaluateParent
  43. EvaluateParenthesis
  44. EvaluatePercent
  45. EvaluatePipeFuncCall
  46. EvaluatePlus
  47. EvaluateProjection
  48. EvaluateRange
  49. EvaluateScore
  50. EvaluateSlash
  51. EvaluateSlice
  52. EvaluateStar
  53. EvaluateStarStar
  54. EvaluateThis
  55. EvaluateThisAttribute
  56. EvaluateUnaryMinus
  57. EvaluateUnaryPlus
  58. Everything
  59. ExclusiveRange
  60. ExecuteQuery
  61. ExponentMarker
  62. Expression
  63. Filter
  64. Fractional
  65. FuncCall
  66. FuncCallArgs
  67. FuncIdentifier
  68. FuncNamespace
  69. HexDigit
  70. HexLetter
  71. Identifier
  72. In
  73. InclusiveRange
  74. Integer
  75. Literal
  76. Match
  77. MatchAnalyzePattern
  78. MatchTokenize
  79. Minus
  80. NewNestedScope
  81. NewRootScope
  82. Not
  83. Null
  84. Number
  85. Object
  86. ObjectAttribute
  87. ObjectAttributes
  88. OperatorCall
  89. Or
  90. Pair
  91. Parent
  92. Parenthesis
  93. PartialCompare
  94. Percent
  95. PipeFuncCall
  96. Plus
  97. Projection
  98. Range
  99. ScientificNotation
  100. Sign
  101. SimpleExpression
  102. SingleEscapeSequence
  103. SingleStringCharacter
  104. Slash
  105. Slice
  106. SourceCharacter
  107. Star
  108. StarStar
  109. String
  110. This
  111. ThisAttribute
  112. TotalCompare
  113. TypeOrder
  114. UnaryMinus
  115. UnaryPlus
  116. UnicodeEscapeSequence
  117. Validate
  118. ValidateAsc
  119. ValidateDesc
  120. ValidateFuncCall
  121. ValidateObject
  122. ValidateObjectAttribute
  123. ValidatePipeFuncCall
  124. WhiteSpace
  125. boost
  126. boostValidate
  127. order
  128. orderValidate
  129. score
  130. scoreValidate
  1. 1Overview
  2. 2Syntax
    1. 2.1JSON Superset
    2. 2.2White Space
    3. 2.3Comments
    4. 2.4Identifier
    5. 2.5Digits
    6. 2.6Expression
  3. 3Execution
    1. 3.1Overview
    2. 3.2Query context
    3. 3.3Scope
    4. 3.4Expression validation
    5. 3.5Expression evaluation
    6. 3.6Score evaluation
    7. 3.7Query 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.2Attribute access expression
    3. 7.3Element access expression
    4. 7.4Slice expression
    5. 7.5Filter expression
    6. 7.6Projection expression
    7. 7.7Pipe function call expression
  8. 8Operators
    1. 8.1And operator
    2. 8.2Or operator
    3. 8.3Not operator
    4. 8.4Equality operators
    5. 8.5Comparison operators
    6. 8.6In operator
    7. 8.7Match operator
    8. 8.8Asc operator
    9. 8.9Desc operator
    10. 8.10Unary plus operator
    11. 8.11Unary minus operator
    12. 8.12Binary plus operator
    13. 8.13Binary minus operator
    14. 8.14Binary star operator
    15. 8.15Binary slash operator
    16. 8.16Binary percent operator
    17. 8.17Binary double star operator
    18. 8.18Dereference operator
  9. 9Precedence and associativity
  10. 10Functions
  11. 11Namespaces
    1. 11.1Global namespace
      1. 11.1.1global::coalesce()
      2. 11.1.2global::count()
      3. 11.1.3global::dateTime()
      4. 11.1.4global::defined()
      5. 11.1.5global::length()
      6. 11.1.6global::references()
      7. 11.1.7global::round()
      8. 11.1.8global::select()
      9. 11.1.9global::string()
      10. 11.1.10global::boost()
      11. 11.1.11global::lower()
      12. 11.1.12global::upper()
  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::contains()
      4. 14.2.4geo::intersects()
      5. 14.2.5geo::distance()
  15. §Index