---
title: "Declare and control-flow"
description: "Learn Aerospike expressions for variable declaration and control-flow using cond, let, def, var, and unknown."
---

# Declare and control-flow

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

Aerospike expressions for declaring variables enable more advanced control-flow within database queries.

This guide explains how to define and use variables using expressions like `cond`, `unknown`, `let`, `def`, and `var`, allowing you to evaluate conditions, manage control-flow, and reuse values efficiently. These expressions can simplify complex logic and improve query performance.

## Ops

#### `cond`

```python
cond(condition0, action0, condition1, action1, ..., default-action)
```

Description: Multi-way branch expression, similar in spirit to a `switch` that picks the first matching case, except each case is its own Boolean test (like an if-else if-else chain). Alternating _condition_ and _action_ operands, plus one final _default_ action. Conditions are evaluated in order; the first that is `true` causes the following action to be evaluated and returned as the value of `cond`, and no later conditions or actions run. If every condition is `false`, the default action is evaluated and returned. All actions (including the default) must produce the same result type, except where `unknown` is allowed by the type rules.

Arguments: | Name | Type |
| --- | --- |
| `condition0` | `boolean-expr` |
| `action0` | `expr` |
| `condition1` | `boolean-expr` |
| `action1` | `expr` |
| `...` | `expr` |
| `default-action` | `expr` |

Returns: `expr`

Introduced: 5.6.0

Example: Classify float bin “price” (a book list price) into string bands aligned with the [bookstore example](https://aerospike.com/docs/develop/expressions/path#bookstore-example) on the path expressions overview: at least 20 is “premium”, at least 12 is “mid”, at least 10 (the top-level “expensive” threshold in that example) is “standard”, otherwise “deal”.

-   [Java](#tab-panel-973)
-   [Python](#tab-panel-974)
-   [C](#tab-panel-975)
-   [Go](#tab-panel-976)
-   [C#](#tab-panel-977)
-   [Node.js](#tab-panel-978)

```java
Expression writeExp = Exp.build(

  Exp.cond(

    Exp.ge(Exp.floatBin("price"), Exp.val(20.0)), Exp.val("premium"),

    Exp.ge(Exp.floatBin("price"), Exp.val(12.0)), Exp.val("mid"),

    Exp.ge(Exp.floatBin("price"), Exp.val(10.0)), Exp.val("standard"),

    Exp.val("deal")));
```

```python
from aerospike_helpers.expressions import Cond, FloatBin, GE, Val

write_exp = Cond(

    GE(FloatBin("price"), 20.0), Val("premium"),

    GE(FloatBin("price"), 12.0), Val("mid"),

    GE(FloatBin("price"), 10.0), Val("standard"),

    Val("deal"),

).compile()
```

```c
as_exp_build(write_exp,

  as_exp_cond(

    as_exp_cmp_ge(

      as_exp_bin_float("price"), as_exp_float(20.0)),

    as_exp_str("premium"),

    as_exp_cmp_ge(

      as_exp_bin_float("price"), as_exp_float(12.0)),

    as_exp_str("mid"),

    as_exp_cmp_ge(

      as_exp_bin_float("price"), as_exp_float(10.0)),

    as_exp_str("standard"),

    as_exp_str("deal")));
```

```go
// Import path matches the Go client examples elsewhere on this doc site (/v6).

// If you use the latest client line, switch to .../aerospike-client-go/v8 (API names unchanged).

// Requires: import as "github.com/aerospike/aerospike-client-go/v6"

writeExp := as.ExpCond(

  as.ExpGreaterEq(as.ExpFloatBin("price"), as.ExpFloatVal(20.0)), as.ExpStringVal("premium"),

  as.ExpGreaterEq(as.ExpFloatBin("price"), as.ExpFloatVal(12.0)), as.ExpStringVal("mid"),

  as.ExpGreaterEq(as.ExpFloatBin("price"), as.ExpFloatVal(10.0)), as.ExpStringVal("standard"),

  as.ExpStringVal("deal"))
```

```csharp
Expression writeExp = Exp.Build(

  Exp.Cond(

    Exp.GE(Exp.FloatBin("price"), Exp.Val(20.0)), Exp.Val("premium"),

    Exp.GE(Exp.FloatBin("price"), Exp.Val(12.0)), Exp.Val("mid"),

    Exp.GE(Exp.FloatBin("price"), Exp.Val(10.0)), Exp.Val("standard"),

    Exp.Val("deal")));
```

```javascript
const exp = Aerospike.exp

const writeExp = exp.cond(

  exp.ge(exp.binFloat('price'), exp.float(20.0)),

  exp.str('premium'),

  exp.ge(exp.binFloat('price'), exp.float(12.0)),

  exp.str('mid'),

  exp.ge(exp.binFloat('price'), exp.float(10.0)),

  exp.str('standard'),

  exp.str('deal'))
```

---

#### `def`

```python
def(name, value)
```

Description: Binds a variable _name_ to the value of an expression for the scope of a sibling [`let`](#let). The body of the `let` reads the binding with [`var`](#var). One or more `def` operands precede the final scoped expression; they are not valid as a stand-alone top-level expression outside `let`.

Arguments: | Name | Type |
| --- | --- |
| `name` | `string-value` |
| `value` | `expr` |

Returns: `expr`

Introduced: 5.6.0

Example: Inside a [`let`](#let), bind float bin `price` to `list_price` and the constant `12.0` to `mid_floor`, then require `list_price >= mid_floor` (aligned with mid-tier list prices in the [bookstore example](https://aerospike.com/develop/expressions/path#bookstore-example)). This pattern shows two `def` bindings before the body.

-   [Java](#tab-panel-979)
-   [Python](#tab-panel-980)
-   [C](#tab-panel-981)
-   [Go](#tab-panel-982)
-   [C#](#tab-panel-983)
-   [Node.js](#tab-panel-984)

```java
Expression exp = Exp.build(

  Exp.let(

    Exp.def("list_price", Exp.floatBin("price")),

    Exp.def("mid_floor", Exp.val(12.0)),

    Exp.ge(Exp.var("list_price"), Exp.var("mid_floor"))));
```

```python
from aerospike_helpers.expressions import Def, FloatBin, GE, Let, Val, Var

exp = Let(

    Def("list_price", FloatBin("price")),

    Def("mid_floor", Val(12.0)),

    GE(Var("list_price"), Var("mid_floor")),

).compile()
```

```c
as_exp_build(predexp,

  as_exp_let(

    as_exp_def("list_price", as_exp_bin_float("price")),

    as_exp_def("mid_floor", as_exp_float(12.0)),

    as_exp_cmp_ge(

      as_exp_var("list_price"),

      as_exp_var("mid_floor"))));
```

```go
// Import path matches the Go client examples elsewhere on this doc site (/v6).

// If you use the latest client line, switch to .../aerospike-client-go/v8 (API names unchanged).

// Requires: import as "github.com/aerospike/aerospike-client-go/v6"

exp := as.ExpLet(

  as.ExpDef("list_price", as.ExpFloatBin("price")),

  as.ExpDef("mid_floor", as.ExpFloatVal(12.0)),

  as.ExpGreaterEq(as.ExpVar("list_price"), as.ExpVar("mid_floor")))
```

```csharp
Expression exp = Exp.Build(

  Exp.Let(

    Exp.Def("list_price", Exp.FloatBin("price")),

    Exp.Def("mid_floor", Exp.Val(12.0)),

    Exp.GE(Exp.Var("list_price"), Exp.Var("mid_floor"))));
```

```javascript
const exp = Aerospike.exp

const writeExp = exp.let(

  ...exp.def('list_price', exp.binFloat('price')),

  ...exp.def('mid_floor', exp.float(12.0)),

  exp.ge(exp.var('list_price'), exp.var('mid_floor')))
```

---

#### `let`

```python
let(def(...), def(...), ..., expr)
```

Description: Introduces a local scope: one or more [`def`](#def) bindings followed by a final _body_ expression. The body may use [`var`](#var) to read those names. The value of the whole `let` is the value of the body; bindings are not visible outside this `let`. Use this when an expensive or bulky sub-expression should be evaluated once and reused.

Arguments: | Name | Type |
| --- | --- |
| `def(...)` | `def-expr` |
| `def(...)` | `def-expr` |
| `...` | `def-exprs` |
| `expr` | `expr` |

Returns: `expr`

Introduced: 5.6.0

Example: Bind float bin `price` to `list_price`, then match records where that price is either below the top-level `expensive` threshold (10) or above a premium cutoff (20), reusing the bound value twice (see the [bookstore example](https://aerospike.com/develop/expressions/path#bookstore-example)).

-   [Java](#tab-panel-985)
-   [Python](#tab-panel-986)
-   [C](#tab-panel-987)
-   [Go](#tab-panel-988)
-   [C#](#tab-panel-989)
-   [Node.js](#tab-panel-990)

```java
Expression exp = Exp.build(

  Exp.let(

    Exp.def("list_price", Exp.floatBin("price")),

    Exp.or(

      Exp.lt(Exp.var("list_price"), Exp.val(10.0)),

      Exp.gt(Exp.var("list_price"), Exp.val(20.0)))));
```

```python
from aerospike_helpers.expressions import Def, FloatBin, GT, Let, LT, Or, Val, Var

exp = Let(

    Def("list_price", FloatBin("price")),

    Or(

        LT(Var("list_price"), Val(10.0)),

        GT(Var("list_price"), Val(20.0)),

    ),

).compile()
```

```c
as_exp_build(predexp,

  as_exp_let(

    as_exp_def("list_price", as_exp_bin_float("price")),

    as_exp_or(

      as_exp_cmp_lt(as_exp_var("list_price"), as_exp_float(10.0)),

      as_exp_cmp_gt(as_exp_var("list_price"), as_exp_float(20.0)))));
```

```go
// Import path matches the Go client examples elsewhere on this doc site (/v6).

// If you use the latest client line, switch to .../aerospike-client-go/v8 (API names unchanged).

// Requires: import as "github.com/aerospike/aerospike-client-go/v6"

exp := as.ExpLet(

  as.ExpDef("list_price", as.ExpFloatBin("price")),

  as.ExpOr(

    as.ExpLess(as.ExpVar("list_price"), as.ExpFloatVal(10.0)),

    as.ExpGreater(as.ExpVar("list_price"), as.ExpFloatVal(20.0))))
```

```csharp
Expression exp = Exp.Build(

  Exp.Let(

    Exp.Def("list_price", Exp.FloatBin("price")),

    Exp.Or(

      Exp.LT(Exp.Var("list_price"), Exp.Val(10.0)),

      Exp.GT(Exp.Var("list_price"), Exp.Val(20.0)))));
```

```javascript
const exp = Aerospike.exp

const writeExp = exp.let(

  ...exp.def('list_price', exp.binFloat('price')),

  exp.or(

    exp.lt(exp.var('list_price'), exp.float(10.0)),

    exp.gt(exp.var('list_price'), exp.float(20.0))))
```

---

#### `unknown`

```python
unknown()
```

Description: Produces the special `unknown` trilean. Meaning depends on where the expression runs. In a [`cond`](#cond) used for an [expression index](https://aerospike.com/docs/database/learn/tutorials/quick-start-expression-index/), the default branch is often `unknown()` so the index stays sparse: only rows whose condition is `true` produce an index key; all others yield `unknown` and are skipped. In an operation expression (read or write inside `operate`), a result of `unknown` fails that sub-operation with error 26 (not applicable); `EXP_READ_EVAL_NO_FAIL` / `EXP_WRITE_EVAL_NO_FAIL` let later operations in the same `operate` call continue. For boolean filters (single-record policies, queries, and [XDR shipping filters](https://aerospike.com/docs/database/manage/xdr/filters/)), only `true` selects or ships the record; `false` and `unknown` do not. During the metadata-only phase of filter evaluation, needing bin data can yield `unknown` and trigger a storage-data phase (see the [execution model](https://aerospike.com/docs/develop/expressions/)); avoid writing filters that unnecessarily depend on that if you want a metadata-only path. If a `cond` _test_ evaluates to `unknown`, the whole `cond` becomes `unknown` and later tests are skipped. Failed arithmetic (for example division by zero) also yields `unknown`. Except for [logic](https://aerospike.com/docs/develop/expressions/logic) operators, when any operand evaluates to `unknown`, the parent expression does too. The value propagates up the expression tree. The common exception is `or`: if at least one boolean child is `true`, `or` resolves to `true` even when other children are `unknown`. See [Disjunction (`or`)](https://aerospike.com/docs/develop/expressions/#disjunction-or) in the expressions overview.

Returns: `unknown`

Introduced: 5.6.0

Example: Sparse [expression index](https://aerospike.com/docs/database/learn/tutorials/quick-start-expression-index/) pattern from the tutorial: if the customer is an adult in a target country, return `age` as the indexed value; otherwise return `unknown()` so the record is not indexed.

-   [Java](#tab-panel-997)
-   [Python](#tab-panel-998)
-   [C](#tab-panel-999)
-   [Go](#tab-panel-1000)
-   [C#](#tab-panel-1001)
-   [Node.js](#tab-panel-1002)

```java
Expression filterExp = Exp.build(

  Exp.cond(

    Exp.and(

      Exp.ge(Exp.intBin("age"), Exp.val(18)),

      Exp.or(

        Exp.eq(Exp.stringBin("country"), Exp.val("Australia")),

        Exp.eq(Exp.stringBin("country"), Exp.val("Canada")),

        Exp.eq(Exp.stringBin("country"), Exp.val("Botswana")))),

    Exp.intBin("age"),

    Exp.unknown()));
```

```python
from aerospike_helpers.expressions import (

    And,

    Cond,

    Eq,

    GE,

    IntBin,

    Or,

    StrBin,

    Unknown,

)

country_is_target = Or(

    Eq(StrBin("country"), "Australia"),

    Eq(StrBin("country"), "Canada"),

    Eq(StrBin("country"), "Botswana"),

)

filter_exp = Cond(

    And(GE(IntBin("age"), 18), country_is_target),

    IntBin("age"),

    Unknown(),

).compile()
```

```c
as_exp_build(filter_exp,

  as_exp_cond(

    as_exp_and(

      as_exp_cmp_ge(

        as_exp_bin_int("age"),

        as_exp_int(18)),

      as_exp_or(

        as_exp_cmp_eq(as_exp_bin_str("country"), as_exp_str("Australia")),

        as_exp_cmp_eq(as_exp_bin_str("country"), as_exp_str("Canada")),

        as_exp_cmp_eq(as_exp_bin_str("country"), as_exp_str("Botswana")))),

    as_exp_bin_int("age"),

    as_exp_unknown()));
```

```go
// Import path matches the Go client examples elsewhere on this doc site (/v6).

// If you use the latest client line, switch to .../aerospike-client-go/v8 (API names unchanged).

// Requires: import as "github.com/aerospike/aerospike-client-go/v6"

filterExp := as.ExpCond(

  as.ExpAnd(

    as.ExpGreaterEq(as.ExpIntBin("age"), as.ExpIntVal(18)),

    as.ExpOr(

      as.ExpEq(as.ExpStringBin("country"), as.ExpStringVal("Australia")),

      as.ExpEq(as.ExpStringBin("country"), as.ExpStringVal("Canada")),

      as.ExpEq(as.ExpStringBin("country"), as.ExpStringVal("Botswana")),

    ),

  ),

  as.ExpIntBin("age"),

  as.ExpUnknown())
```

```csharp
Expression filterExp = Exp.Build(

  Exp.Cond(

    Exp.And(

      Exp.GE(Exp.IntBin("age"), Exp.Val(18)),

      Exp.Or(

        Exp.EQ(Exp.StringBin("country"), Exp.Val("Australia")),

        Exp.EQ(Exp.StringBin("country"), Exp.Val("Canada")),

        Exp.EQ(Exp.StringBin("country"), Exp.Val("Botswana")))),

    Exp.IntBin("age"),

    Exp.Unknown()));
```

```javascript
const exp = Aerospike.exp

const filterExp = exp.cond(

  exp.and(

    exp.ge(exp.binInt('age'), exp.int(18)),

    exp.or(

      exp.eq(exp.binStr('country'), exp.str('Australia')),

      exp.eq(exp.binStr('country'), exp.str('Canada')),

      exp.eq(exp.binStr('country'), exp.str('Botswana')))),

  exp.binInt('age'),

  exp.unknown())
```

---

#### `var`

```python
var(name)
```

Description: Reads a value bound by [`def`](#def) inside the same [`let`](#let). The _name_ must match a preceding `def` in that `let`. `var` is only meaningful within the body of that `let`; it does not access bins or outer scope by itself.

Arguments: | Name | Type |
| --- | --- |
| `name` | `string-value` |

Returns: `expr`

Introduced: 5.6.0

Example: Inside a [`let`](#let), bind float bin `price` once, then use `var(“list_price”)` twice to test `10 < list_price < 13` (strict between the [bookstore](https://aerospike.com/develop/expressions/path#bookstore-example) `expensive` threshold and a mid-tier upper bound).

-   [Java](#tab-panel-991)
-   [Python](#tab-panel-992)
-   [C](#tab-panel-993)
-   [Go](#tab-panel-994)
-   [C#](#tab-panel-995)
-   [Node.js](#tab-panel-996)

```java
Expression exp = Exp.build(

  Exp.let(

    Exp.def("list_price", Exp.floatBin("price")),

    Exp.and(

      Exp.lt(Exp.val(10.0), Exp.var("list_price")),

      Exp.lt(Exp.var("list_price"), Exp.val(13.0)))));
```

```python
from aerospike_helpers.expressions import And, Def, FloatBin, Let, LT, Val, Var

exp = Let(

    Def("list_price", FloatBin("price")),

    And(

        LT(Val(10.0), Var("list_price")),

        LT(Var("list_price"), Val(13.0)),

    ),

).compile()
```

```c
as_exp_build(predexp,

  as_exp_let(

    as_exp_def("list_price", as_exp_bin_float("price")),

    as_exp_and(

      as_exp_cmp_lt(as_exp_float(10.0), as_exp_var("list_price")),

      as_exp_cmp_lt(as_exp_var("list_price"), as_exp_float(13.0)))));
```

```go
// Import path matches the Go client examples elsewhere on this doc site (/v6).

// If you use the latest client line, switch to .../aerospike-client-go/v8 (API names unchanged).

// Requires: import as "github.com/aerospike/aerospike-client-go/v6"

exp := as.ExpLet(

  as.ExpDef("list_price", as.ExpFloatBin("price")),

  as.ExpAnd(

    as.ExpLess(as.ExpFloatVal(10.0), as.ExpVar("list_price")),

    as.ExpLess(as.ExpVar("list_price"), as.ExpFloatVal(13.0))))
```

```csharp
Expression exp = Exp.Build(

  Exp.Let(

    Exp.Def("list_price", Exp.FloatBin("price")),

    Exp.And(

      Exp.LT(Exp.Val(10.0), Exp.Var("list_price")),

      Exp.LT(Exp.Var("list_price"), Exp.Val(13.0)))));
```

```javascript
const exp = Aerospike.exp

const writeExp = exp.let(

  ...exp.def('list_price', exp.binFloat('price')),

  exp.and(

    exp.lt(exp.float(10.0), exp.var('list_price')),

    exp.lt(exp.var('list_price'), exp.float(13.0))))
```

---