AEL paths and navigation
For the complete documentation index see: llms.txt
All documentation pages available in markdown.
Reference page: part of the AEL reference. Covers how AEL navigates from a record to a bin value and into nested collection data. See Applies to on the overview page for SDK and Database version requirements.
Record and bin prefix
Every path starts with $:
$ /* current record */$.binName /* scalar bin */$.profile.name /* map key access */$.scores.[0] /* list index access */$.data.users.[2].name /* deeply nested */| Form | Meaning |
|---|---|
$ | Current record |
$.binName | Bin named binName |
$."quoted\nname" | Bin whose name requires quoting or escapes |
$.a.b.c | Navigate map keys b, c under bin a |
$.a.[0] | Navigate list index 0 under bin a |
Navigation is strict by default: missing intermediate keys or out-of-range indices cause failure unless a create-order suffix (:KEY_ORDERED, :SORTED, and so on) applies on that segment.
Bin type inference
The first context element determines the bin type:
| Path | Inferred type |
|---|---|
$.x.name | Map (first context is identifier) |
$.x.[0] | List (first context is [) |
$.x > 5 | Scalar (no context) |
Map access
$.profile.name /* string key (dot notation) */$.profile.'special-key' /* quoted string key (dot notation, for keys with special chars) */$.m.{@1} /* integer key (bare `.1` is not a legal identifier segment) */$.m.{1} /* map by index */$.m.{='bb'} /* map by value */$.m.{#1} /* map by rank */[…] bracket notation is reserved for list selectors; it is not an alternate syntax for map key access. Use dot notation, quoted dot notation, or the {@key} selector for map keys. For the full selector reference (ranges, lists, inverted forms), see Map selectors {…}.
Quoted notation for map key names
These identifiers are grammar keywords or verb-like tokens the parser
otherwise expects at that position. Unlike the reserved words in Lexical rules,
most of these are not reserved everywhere in AEL — type, set, insert, and so on are valid
method names elsewhere — but using one as a bare dotted map key segment causes a
Debug AEL expressions. Always use quoted key notation for a map key with one of these names:
andappendcleardefaulterrorexclusivefalsegetinincrementinsertletnotorremovereturnsetsortthentruetypeunknownwhen
/* Fails as 'type' is a reserved word: */$.metadata.type == 'fixture'/* Correct: quoted key notation bypasses keyword parsing */$.metadata.'type' == 'fixture'List access
$.scores.[0] /* by index */$.scores.[-1] /* last element */$.scores.[=42] /* by value */$.scores.[#0] /* by rank (lowest) */For the full list selector reference (ranges, lists, inverted forms, and relative selectors), see List selectors […].
Parenthesised expressions
| Form | Meaning |
|---|---|
(expr) | Grouping in ordinary expressions |
(expr).segment… / (expr).method(…) | Use a parenthesised expression as the left side of further .… navigation or method calls |
terminal(expr) | Full expressions in function-call arguments, for example setTo($.otherBin) or bitSet(offset: 0, size: 8, value: $.data) |
When .method() must follow (…): a dot chain can continue after () only when the left side is already a bin path ($.bin…), a blob literal, a standalone function call (max(…), abs(…)), or an earlier method chain. Record metadata functions and other general expressions must be wrapped: (expr).method(…), for example ($.ttl()).toString(), not $.ttl().toString() (parse error).
Parenthesised expressions aren’t supported inside selector brackets {…} or […] in place of literals, for example $.m.{($.idx)} is not valid.
Collection literals are static only: list and map literals ([…], {…} in value position) must contain literals, not bin paths or other $ expressions. For example, [$.hllA, $.hllB] as an argument to hllUnionCount is a parse error (see HLL path functions). This will change in a later release.
Wildcard iteration
| Form | Meaning |
|---|---|
* | Between dots: iterate all children at this map or list level |
.* | After a path segment: all children of that segment |
.*[?(predicate)] | Children matching a Boolean predicate |
Wildcard * as a path segment is distinct from * as a literal value inside […] or {…}.
When * is the first segment after a bin name, it does not pin the bin’s container type, unlike a list selector or map-key segment. Pin the bin explicitly: $.bin:LIST.*… or $.bin:MAP.*… (see Type inference).
For loop variables (@, @key, @index) used inside *[?(…)] predicates and .modify(…) bodies, see Loop variables.
Key list with filter chain
Restrict a map to specific keys, then filter those entries at the current level:
$.map.{@"key1","key2","key3"}&[?(predicate)]&[?( must be contiguous: no spaces between &, [, and ?; no extra . before &.
Field projection after wildcard
After .* or .*[?(…)], select a named field on each matched child with .fieldName:
$.store:MAP.*.*[?(@.inStock == true)].titleCollection create-order suffixes
These suffixes attach to collection path segments, including the first segment after $. when a top-level container may need to be created. Type pins :MAP / :LIST (see Types and type suffixes) remain typing-only. Each flag tells the server how to create a missing container when navigation or a write needs it. Create-order flags attach to the segment where the missing container should be created; each nested level carries its own flag independently, for example $.a.b:SORTED.[0]:KEY_ORDERED.c.setTo(5) creates a sorted list at b, then a key-ordered map at index 0.
At most one create-order flag from the following table may follow a single path segment. Combining two is a parse error. :PERSIST_INDEX (see Postfix flags) may stack with a map create-order flag on the bin root only. Other flags may also stack, for example :LOCAL.
| Suffix | Missing value | Existing value |
|---|---|---|
| (none) | Fails — the collection data type (CDT) is not automatically created | Treat as existing map or list |
:KEY_ORDERED | Create empty key-ordered map | Treat as map (no-op for creation) |
:KEY_VALUE_ORDERED | Create empty key-value ordered map | Treat as map (no-op for creation) |
:UNORDERED | Create empty unordered map | Treat as map (no-op for creation) |
:SORTED | Create empty sorted (ordered) list | Treat as list (no-op for creation) |
:UNSORTED | Create empty unsorted (unordered) list — bounded (see Bounded list writes); default when a list create is needed | Treat as list (no-op for creation) |
:UNSORTED_PAD | Create empty unsorted list, with nil-padding when navigation or a write needs a distant index (see Bounded list writes) | Treat as list (no-op for creation) |
Map segments use :KEY_ORDERED, :KEY_VALUE_ORDERED, and :UNORDERED. List segments use :SORTED, :UNSORTED, and :UNSORTED_PAD. At most one of :SORTED, :UNSORTED, and :UNSORTED_PAD may follow a list segment.
Bounded list writes (default)
Bounded is the default at two levels, controlled together unless :UNSORTED_PAD opts out:
- Context create: when a missing list container is created on the navigation path,
:UNSORTED(the default list create-order) does not nil-pad skipped slots. - List write ops: when writing past the end of an existing, unsorted list (
setTo,insert,add,insertItems), the server does not nil-pad to reach a sparse index. Writes atindex == list sizeare contiguous append, including bulkinsertItemsat the end (all elements append in one call). Bounded forbids sparse growth (index strictly greater than size), not growth in general.
There is no :BOUNDED suffix — bounded needs no name. :UNSORTED_PAD is the single opt-out: it enables nil-padding on both context create and list-write padding.
Sorted lists can never be sparse, so they never require this flag.
/* Nested create: sorted list at 'b', then key-ordered map at index 0 */$.a.b:SORTED.[0]:KEY_ORDERED.c.setTo('x')
/* Sparse create (see the :UNSORTED_PAD caution earlier in this section) */$.sparse:UNSORTED_PAD.[1000000].setTo('value')
/* Bare-bin write creates a missing map bin via putItems, not the :MAP type pin */$.m:MAP.putItems({k: v})Create-order suffix restrictions by terminal kind
Create-order flags (:KEY_ORDERED, :KEY_VALUE_ORDERED, :UNORDERED, :SORTED, :UNSORTED, :UNSORTED_PAD) may appear only on write paths that can materialize missing containers from collection data type (CDT) context-create bits. They are not allowed on read terminals, and are not allowed on write terminals that do not create containers (modify(), remove()). A create-order suffix on such paths is a parse error:
- Suffix on a single-select segment. The suffix must attach to a single-select segment, not a wildcard, filter, or multi-key/rank/index/value list. Invalid:
$.m.*:KEY_ORDERED.k.setTo(1),$.m.{@a,b}:KEY_ORDERED.k.setTo(1). - Every segment before the leaf must be single-select. An earlier wildcard or multi-select selector invalidates the whole path even when the suffix sits on a later segment. Invalid:
$.m.*.k:KEY_ORDERED.setTo(1). - Terminals that do not create containers reject create-order.
modify()andremove()never accept create-order flags, even on fully single-select paths. Invalid:$.m.p1:KEY_ORDERED.k.modify(@ + 1),$.m.p1:KEY_ORDERED.k.remove().
When an absent CDT context segment (a path step missing in the bin) should be tolerated for write terminals that do not create containers, use :NO_FAIL instead, for example $.m.p1.{@a,b}.remove():NO_FAIL. See Postfix flags.
Qualifying create-order paths honor context-create bits at compile time. Read terminals and non-creating write terminals reject create-order because they never create containers..
Next steps
- Selectors and loop variables — the full
{…}/[…]selector punctuation reference - Functions and terminals — path read and write terminals
- AEL reference overview — lexical rules, literals, and types