--- 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-996) - [Python](#tab-panel-997) - [C](#tab-panel-998) - [Go](#tab-panel-999) - [C#](#tab-panel-1000) - [Node.js](#tab-panel-1001) ```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-1002) - [Python](#tab-panel-1003) - [C](#tab-panel-1004) - [Go](#tab-panel-1005) - [C#](#tab-panel-1006) - [Node.js](#tab-panel-1007) ```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-1008) - [Python](#tab-panel-1009) - [C](#tab-panel-1010) - [Go](#tab-panel-1011) - [C#](#tab-panel-1012) - [Node.js](#tab-panel-1013) ```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/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/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/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`. Returns: `unknown` Introduced: 5.6.0 Example: Sparse [expression index](https://aerospike.com/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-1020) - [Python](#tab-panel-1021) - [C](#tab-panel-1022) - [Go](#tab-panel-1023) - [C#](#tab-panel-1024) - [Node.js](#tab-panel-1025) ```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