---
title: "AEL selectors and loop variables"
description: "AEL reference: map selectors, list selectors, inverted selections, loop variables, and selector punctuation."
---

# AEL selectors and loop variables

> For the complete documentation index see: [llms.txt](https://aerospike.com/docs/llms.txt)
> 
> All documentation pages available in markdown.

Reference page: part of the [AEL reference](https://aerospike.com/docs/develop/client/sdk/concepts/ael/reference). Covers the full `{…}` (map) and `[…]` (list) selector punctuation, including plural, range, and inverted forms. See [Applies to](https://aerospike.com/docs/develop/client/sdk/concepts/ael/reference#applies-to) on the overview page for SDK and Database version requirements.

_Key range vs. index range: the marker distinguishes them, not the delimiter._ Every dimension uses the same colon (`:`) for ranges and comma (`,`) for lists. The leading marker selects the dimension:

-   No marker selects by _index_ (`{0:3}`).
-   `@` selects by _key_ (`{@a:d}`).
-   `=` selects by _value_ (`{=a:d}`).
-   `#` selects by _rank_ (`{#1:5}`).

There is no dash (`-`) selector token in AEL.

```plaintext
/* String key range from "room1" up to (but not including) "room3": */

$.rooms.{@'room1':'room3'}

/* Count of entries in that range: */

$.rooms.{@'room1':'room3'}.count()

/* WRONG: no marker means index dimension, and "room1"/"room3" are not indexes: */

$.rooms.{room1:room3}   ← parse error
```

```plaintext
$.m.{@'a':'d'}                  /* key range [a, d) */

$.m.{@'a','b','c'}              /* key list */

$.m.{0:3}                       /* index range */

$.m.{=10:20}                    /* value range */

$.m.{#:3}                       /* top 3 by rank (lowest 3 ranks) */

$.l.[1:5]                       /* list index range */

$.l.[=1,2,3]                    /* list value list */

$.l.[#0:3]                      /* list rank range */
```

## Map selectors `{…}`

The first character after `{` sets the **dimension**: _(none)_ = index, `@` = key, `=` = value, `#` = rank.

Selector operands are static literals only (see [Collection literals are static only](https://aerospike.com/docs/develop/client/sdk/concepts/ael/reference/paths#parenthesised-expressions)), not parenthesised expressions. Operand types by dimension:

| Dimension | Operand types |
| --- | --- |
| Key (`@…`) | `INT`, `STRING`, `BLOB` literals, `NIL`, `INF` |
| Value (`=…`) | Any scalar literal: `INT`, `FLOAT`, `STRING`, `BOOL`, `BLOB`, `NIL`, `INF` |
| Index (`{n}`) | `INT` only — a `BLOB` or other non-integer literal is a parse error |
| Rank (`#…`) | `INT` only — a `BLOB` or other non-integer literal is a parse error |

Examples with `BLOB` keys: `$.perms.{@x'dead'}`, `$.caps.{@x'aa':x'ff'}`, `$.caps.{@x'aa',x'bb'}`, `$.scores.{=x'cafe'}`.

In the following selector tables, **—** means that form isn’t available for that dimension.

| Dimension | Singular | Range | Open-start | Open-end | List | Inverted range | Inverted list |
| --- | --- | --- | --- | --- | --- | --- | --- |
| Index | `{1}` | `{1:5}` | `{:5}` | `{1:}` | — | `{!1:5}` | — |
| Key | `'key'` or `{@'key'}` | `{@x'ab':x'def0'}` | `{@:'d'}` | `{@'a':}` | `{@'a','b','c'}` | `{!@'a':'d'}` | `{!@'a','b','c'}` |
| Value | `{=a}` | `{=a:d}` | `{=:d}` | `{=a:}` | `{=a,b,c}` | `{!=a:d}` | `{!=1,2,3}` |
| Rank | `{#1}` | `{#1:5}` | `{#:5}` | `{#1:}` | — | `{!#1:5}` | — |

Relative (map):

| Form | Meaning |
| --- | --- |
| `{#-1:1~ref}` | Rank-relative range |
| `{#-2:~ref}` | Rank-relative open end |
| `{!#-1:~ref}` | Inverted rank-relative |
| `{0:1~key}` | Index range relative to key |
| `{0:~key}` | Index open end relative to key |
| `{!0:1~key}` | Inverted index-relative range |

Trailing comma: `{@k,}` is multi-select with one key (invertible as `{!@k,}`); `{@k}` alone is singular and non-invertible (zero or one element). The same convention applies to the value dimension: `{=a,}` / `{!=a,}` is a one-element value list, while `{=a}` alone is singular.

Intervals: index and rank ranges use begin-inclusive, end-exclusive semantics.

## List selectors `[…]`

After `[`, if the next non-whitespace character is `=` the selector is **value** dimension; if `#` then **rank**; if `!` then inverted (re-parse the remainder); otherwise **index**.

Selector operands follow the same rules as the [map selectors](#map-selectors) described earlier: key/value/rank/index literal types as listed there. Examples: `$.payload.[='two words']`, `$.payload.[=x'aa':x'ff']`, `$.payload.[!=172,]`.

In the following table, **—** again means that form isn’t available for that dimension.

| Dimension | Singular | Range | Open-start | Open-end | List | Inverted range | Inverted list |
| --- | --- | --- | --- | --- | --- | --- | --- |
| Index | `[1]` | `[1:5]` | `[:5]` | `[1:]` | — | `[!1:5]` | — |
| Value | `[=a]` | `[=a:d]` | `[=:d]` | `[=a:]` | `[=a,b,c]` | `[!=a:d]` | `[!=a,b,c]` |
| Rank | `[#1]` | `[#1:5]` | `[#:5]` | `[#1:]` | — | `[!#1:5]` | — |

Relative (list):

| Form | Meaning |
| --- | --- |
| `[#-3:-1~ref]` | Rank-relative range |
| `[#-2:~ref]` | Rank-relative open end |
| `[!#-3:-1~ref]` | Inverted rank-relative |

Trailing comma (value dimension): `[=a,]` is a multi-select with one value (invertible as `[!=a,]`); `[=a]` alone is singular.

Intervals: index and rank ranges use begin-inclusive, end-exclusive semantics.

## Inverted selections (prefix `!`)

```plaintext
$.m.{!@a:d}                     /* everything except keys a-c */

$.l.[!0:3]                      /* everything except indices 0-2 */

$.m.{!=temp,draft}              /* everything except entries with these values */
```

## Loop variables

Valid only inside `*[?(…)]` filter predicates and `.modify(…)` bodies. Requires an enclosing `*` wildcard in scope (see [Wildcard iteration](https://aerospike.com/docs/develop/client/sdk/concepts/ael/reference/paths#wildcard-iteration)).

| Form | Meaning |
| --- | --- |
| `@` | Current iteration element value (for example, the map value if iterating over map keys) |
| `@.field` | Navigate into current element (map key) |
| `@.[n]` | List index within current element |
| `@key` | Parent map key (metadata; no dot) |
| `@index` | Parent list index (metadata; no dot) |

Nested sub-expressions inside filter arguments are not allowed: no filter can nest inside another filter’s path argument. Each `*[?(…)]` level has its own `@` scope.

```plaintext
$.map.{@"key1","key2","key3"}&[?(@ > 100)]

$.store:MAP.*.*[?(@.inStock == true)].title

$.store.book.*.price.modify(@ * 0.9)
```

Relative selectors (map and list):

```plaintext
$.m.{#-1:1~ref}       /* rank-relative range */

$.m.{0:1~key}         /* index range relative to key */

$.l.[#-3:-1~ref]      /* list rank-relative range */
```

## Selector punctuation quick reference

| Token | In `{…}` / `[…]` |
| --- | --- |
| _(none)_ | Index dimension |
| `@` | Map key dimension (in `{…}` only) |
| `=` | Value dimension |
| `#` | Rank dimension |
| `:` | Range separator |
| `,` | List / multi-select |
| `~` | Relative-to binding |
| `!` immediately after `{` or `[` | Inverted selection |

## Next steps

-   [Operators](https://aerospike.com/docs/develop/client/sdk/concepts/ael/reference/operators) — comparison, logical, arithmetic, and precedence
-   [Functions and terminals](https://aerospike.com/docs/develop/client/sdk/concepts/ael/reference/functions) — path read and write terminals that follow a selector
-   [Paths and navigation](https://aerospike.com/docs/develop/client/sdk/concepts/ael/reference/paths) — everyday map and list access