This document defines the v1 grammar and semantics for the native filter command.
filter is a built-in JSON transformation command for CosmosDBShell. It uses a jq-inspired expression language, but it is not a jq implementation and does not attempt full jq compatibility.
- Support common JSON shaping and filtering workflows inside CosmosDBShell.
- Preserve structured pipeline results so
filtercan feed later commands. - Keep the language small enough to implement and document clearly.
- Full jq compatibility.
- jq modules, variables, function definitions, or streaming mode.
- Regex support in v1.
- Update-assignment operators such as
|=,+=,del, orsetpath. - Exact jq multi-result generator semantics.
The command surface for v1 is:
filter <expression>
expressionis required.- The expression is usually quoted at the shell level, for example:
filter '.items[0]'. - Input comes from the current pipeline value.
- Output is written back into the shell's structured command result.
The language operates on JSON values:
null- booleans
- numbers
- strings
- arrays
- objects
The current pipeline value is referred to as ..
filter evaluates expressions eagerly.
- Expressions consume one input JSON value.
- Expressions produce one JSON value.
- Operations that would naturally produce multiple values in jq are materialized as arrays in v1 when needed for shell-safe behavior.
- Intermediate results remain JSON values and can be passed to downstream commands.
Whitespace may appear between tokens and is ignored unless it appears inside a string literal.
Identifiers are used for object shorthand fields and builtin names.
identifier = letter , { letter | digit | '_' }
Examples:
iditemssort_by
Supported literals:
nulltruefalse- integer and decimal numbers
- double-quoted strings with JSON-style escapes
Examples:
nulltrue423.14"active"
The grammar below uses a compact EBNF-style notation.
filter-expression = expression ;
expression = pipe-expression ;
pipe-expression = or-expression , { '|' , or-expression } ;
or-expression = and-expression , { '||' , and-expression } ;
and-expression = xor-expression , { '&&' , xor-expression } ;
xor-expression = equality-expression , { '^' , equality-expression } ;
equality-expression
= comparison-expression , { ( '==' | '!=' ) , comparison-expression } ;
comparison-expression
= additive-expression ,
{ ( '<' | '<=' | '>' | '>=' ) , additive-expression } ;
additive-expression
= multiplicative-expression ,
{ ( '+' | '-' ) , multiplicative-expression } ;
multiplicative-expression
= power-expression ,
{ ( '*' | '/' | '%' ) , power-expression } ;
power-expression = unary-expression , [ '**' , power-expression ] ;
unary-expression = ( '!' | '-' | '+' ) , unary-expression
| primary-expression ;
primary-expression = path-expression
| literal
| builtin-expression
| array-constructor
| object-constructor
| '(' , expression , ')' ;
path-expression = '.' , { path-segment } ;
path-segment = '.' , identifier , [ '?' ]
| '.' , string-literal , [ '?' ]
| '[' , string-literal , ']' , [ '?' ]
| '[' , integer-literal , ']' , [ '?' ]
| '[' , ']' , [ '?' ] ;
builtin-expression = 'length'
| 'keys'
| 'type'
| 'contains' , '(' , expression , ')'
| 'map' , '(' , expression , ')'
| 'select' , '(' , expression , ')'
| 'sort_by' , '(' , expression , ')' ;
array-constructor = '[' , [ expression , { ',' , expression } ] , ']' ;
object-constructor = '{' , [ object-field , { ',' , object-field } ] , '}' ;
object-field = identifier
| identifier , ':' , expression
| string-literal , ':' , expression ;
. returns the current input unchanged.
Examples:
.. | type
.name reads the property name from an object.
- If the input is an object and the property exists, the property value is returned.
- If the property does not exist, v1 returns
null. - If the input is not an object, evaluation fails unless optional access is used.
Examples:
.id.items.metadata.status.["Volcano Name"]."Volcano Name"
.name? behaves like .name, but it suppresses type/access errors.
- If the input is not an object, the result is
null. - If the property does not exist, the result is
null.
.[n] reads the array element at zero-based index n.
- If the input is an array and the index exists, the element is returned.
- If the index is out of range, the result is
null. - If the input is not an array, evaluation fails unless optional access is used.
Examples:
.[0].items[0]
.[n]? suppresses type/access errors and returns null when the access cannot be satisfied.
.[] iterates the values of an array.
In v1, iteration is materialized for shell-safe semantics:
- if the input is an array, the result is an array containing the iterated values
- if the input is an object,
.[]is not supported in v1 unless object iteration is explicitly added later - if the input is not an array, evaluation fails unless optional iteration is used
Examples:
.items[][.items[] | .id]
.[]? returns null when the input is not an array.
a | b evaluates a first, then evaluates b against the result of a.
Examples:
.items | length.items | map(.id).items[0] | {id, status}
Comparisons produce booleans.
Supported operators:
==!=<<=>>=
Examples:
.status == "active".count > 10
In addition to comparisons, v1 supports the shell's standard arithmetic and logical operators inside a filter expression. Each operand is an expression that is evaluated against the current input.
Arithmetic operators (operate on numbers):
+addition-subtraction*multiplication/division%modulo**power (right-associative)- unary
-and+
Logical operators (operate on booleans):
&&and (short-circuits)||or (short-circuits)^xor!not (unary)
Precedence, from lowest to highest binding, is:
| < || < && < ^ < == != < < <= > >= < + - < * / % < ** < unary ! - +.
Use parentheses to group sub-expressions, for example (.a + .b) * .c.
Examples:
.price * .quantity.count + 1.status == "active" && .count > 10!(.disabled)
[expr1, expr2, ...] evaluates each expression against the current input and constructs a JSON array from the results.
Examples:
[.id, .status][.items[0], .items[1]]
{...} constructs a JSON object.
Supported forms:
- shorthand field capture:
{id, status} - explicit mapping:
{id: .id, state: .status} - string keys:
{"item-id": .id}
For shorthand fields, {id} is equivalent to {id: .id}.
Returns the length of the input value.
- array: number of elements
- object: number of properties
- string: number of characters
- null:
0 - number and boolean: runtime error in v1
Examples:
.items | length.name | length
Returns an array of object property names.
- input must be an object
- result ordering should be deterministic
Example:
.item | keys
Returns one of the strings:
"null""boolean""number""string""array""object"
Example:
.payload | type
Evaluates expr against the current input and returns whether the input contains the resulting value.
v1 behavior:
- string contains string substring
- array contains element by JSON equality
- object contains object subset by matching keys and values
- other types use JSON equality
Examples:
.tags | contains("prod").item | contains({status: "active"})
Applies expr to each element of the input array and returns an array of transformed values.
- input must be an array
- each element becomes the current input while evaluating
expr
Examples:
.items | map(.id).items | map({id, status})
Filters an input array by applying expr to each element and keeping elements where the result is true.
- input must be an array
expris evaluated per element- only boolean
truekeeps an element in v1
Examples:
.items | select(.status == "active").items | select(.count > 10)
Sorts an input array using the value produced by expr for each element.
- input must be an array
- keys must be mutually comparable
- stable sorting is preferred
Keys of the same JSON type are ordered naturally: numbers numerically,
strings by ordinal comparison, booleans as false < true, and null
as equal to null. When keys have different JSON types, they are ordered
by a fixed kind rank:
null < false < true < number < string < array < object
Arrays and objects that share a rank are compared by their raw JSON text, which is deterministic but not semantically meaningful; prefer like-typed, scalar sort keys.
Examples:
.items | sort_by(.id).items | sort_by(.timestamp)
- Property access requires an object unless optional access is used.
- Index access and array builtins require an array unless optional access is used.
map,select, andsort_byrequire arrays.keysrequires an object.lengthsupports arrays, objects, strings, and null. Numbers and booleans raise a runtime error.- Comparisons require values that the implementation can compare deterministically.
- Cross-type ordering for
sort_byand relational comparisons uses the fixed kind ranknull<false<true< number < string < array < object.
v1 should distinguish these error classes:
Invalid syntax in the expression.
Examples:
.items[{id: }
Syntax that looks jq-like but is outside the v1 contract.
Examples:
.items[] | .id, .statusreduce .items[] as $x (...).name |= "x"test("abc")
The diagnostic should say the construct is not supported by filter v1 and should suggest using jq when full jq behavior is required.
The expression is syntactically valid but is applied to the wrong input shape.
Examples:
.idapplied to an arraymap(.id)applied to an object
.
.items[0]
.items[0]?.id
.items | length
.items | map(.id)
.items | select(.status == "active")
.items | sort_by(.id)
.items | map({id, status})
{id, status}
[.id, .status]
.[] | .id, .status
reduce .items[] as $item (0; . + $item)
.items |= map(.id)
def pickId: .id; pickId
test("^abc")
inputs
The intended implementation model for v1 is:
- parse into a small AST
- evaluate against
JsonElement - materialize iteration results as arrays where needed
- store the final JSON value back into
CommandState.Result
This language should be implemented as a native shell feature, not as a compatibility layer over the external jq executable.
- Should object iteration with
.[]be supported? - Should
select(expr)accept jq-like truthiness or only stricttrue? - Should negative array indices be supported?
- Should array slicing be added?
- Should string helper functions be added before regex support?
- Should multi-result semantics be expanded beyond array materialization?