Path expressions usage examples
This page contains advanced examples of using path expressions to select elements from a document modeled in Aerospike as nested map and list structures.
The quickstart guide covers a common use case: filtering and selecting products and their in-stock variants. This section highlights advanced capabilities unlocked by path expressions.
Accessing iteration data from a map key, list index or element value with a LoopVar
When using a path expression to iterate over map or lsit elements, you can assign data from the element in this iteration to loop variables.
Example: Select only products whose key starts with SKU 1000.
Exp filterOnKey = Exp.regexCompare("10000.*", RegexFlag.NONE, Exp.stringLoopVar(LoopVarPart.MAP_KEY));
// OperationRecord record = client.operate(null, key, CdtOperation.selectByPath("catalog", Exp.SELECT_MATCHING_TREE, CTX.allChildren(), CTX.allChildrenWithFilter(filterOnKey)));
System.out.println(record.getMap("catalog"));import aerospikefrom aerospike_helpers import expressions as exp, cdt_ctxfrom aerospike_helpers.operations import operations
filter_on_key = exp.CmpRegex(aerospike.REGEX_NONE, "10000.*", exp.LoopVarStr(aerospike.EXP_LOOPVAR_KEY)).compile()
ctx = [ cdt_ctx.cdt_ctx_all_children(), cdt_ctx.cdt_ctx_all_children_with_filter(filter_on_key)]# Operationops = [ operations.select_by_path( "catalog", ctx, aerospike.EXP_PATH_SELECT_MATCHING_TREE )](key, meta, bins) = client.operate(key, ops)import jsonprint(json.dumps(bins["catalog"], indent=4))filterOnKey := aero.ExpRegexCompare("10000.*", aero.ExpRegexFlagNONE, aero.ExpStringLoopVar(aero.MAP_KEY))// Operationrecord, err := client.Operate(nil, key, aero.SelectByPath("catalog", aero.EXP_PATH_SELECT_MATCHING_TREE, aero.CtxAllChildren(), aero.CtxAllChildrenWithFilter(filterOnKey), ),)
fmt.Println(record.Bins["catalog"])// Filteras_exp_build(filter_on_key, as_exp_cmp_regex( 0, "1000.*", as_exp_loopvar_str(AS_EXP_LOOPVAR_KEY)));
if (!filter_on_key) { goto fail_filter_on_key;}
// Operation
as_cdt_ctx ctx;as_cdt_ctx_inita(&ctx, 2);as_cdt_ctx_add_all_children(&ctx);as_cdt_ctx_add_all_children_with_filter(&ctx, filter_on_key);
as_operations ops;as_operations_inita(&ops, 1);status = as_operations_select_by_path(&err, &ops, "catalog", &ctx, AS_EXP_PATH_SELECT_MATCHING_TREE);if (status != AEROSPIKE_OK) { goto fail_select_by_path;}
as_record* rec = NULL;status = aerospike_key_operate(&as, &err, NULL, &key, &ops, &rec);if (status != AEROSPIKE_OK) { goto fail_key_operate;}
// Print in JSON format
as_map* map = as_record_get_map(rec, "catalog");if (map) { char* map_str = as_val_tostring((as_val*)map); log("%s\n", map_str); free(map_str);} else { log("No data returned\n");}Exp filterOnKey = Exp.RegexCompare("10000.*", RegexFlag.NONE, Exp.StringLoopVar(LoopVarPart.MAP_KEY) );
// Operation Record record = client.Operate(null, key, CDTOperation.SelectByPath("catalog", SelectFlag.MATCHING_TREE, CTX.AllChildren(), CTX.AllChildrenWithFilter(filterOnKey) ) );Console.WriteLine(System.Text.Json.JsonSerializer.Serialize((Dictionary<object, object>)record.Map("catalog"), new System.Text.Json.JsonSerializerOptions { WriteIndented = true }));const filterOnKey = exp.cmpRegex(Aerospike.regex.BASIC, "10000.*", exp.loopVarStr(exp.loopVarPart.KEY));
const ctx = new Context().addAllChildren().addAllChildrenWithFilter(filterOnKey)
const ops = [ op.selectByPath('catalog', exp.pathSelectFlags.MATCHING_TREE, ctx)]
const result = await client.operate(key, ops)
console.log(result.bins.catalog)Expected output:
{ "inventory": { "10000001": { ... }, "10000002": { ... } }}✅ Only products whose keys start with 1000 are included.
Use alternative return modes with SelectFlags
Sometimes you don’t want the full tree, but just the map keys or values.
Example: Return only the SKUs of in-stock variants for featured products that follow a map/dictionary structure.
// OperationRecord readResult = client.operate(null, key, CdtOperation.selectByPath("catalog", Exp.SELECT_MAP_KEY | Exp.SELECT_NO_FAIL, CTX.allChildren(), CTX.allChildrenWithFilter(filterOnFeatured), CTX.mapKey(Value.get("variants")), CTX.allChildrenWithFilter(filterOnVariantInventory) ));
System.out.println(readResult.getList("catalog"));// Operationops = [ operations.select_by_path( "catalog", [ cdt_ctx.cdt_ctx_all_children(), cdt_ctx.cdt_ctx_all_children_with_filter(filter_on_featured), cdt_ctx.cdt_ctx_map_key('variants'), cdt_ctx.cdt_ctx_all_children_with_filter(filter_on_variant_inventory) ], aerospike.EXP_PATH_SELECT_MAP_KEY | aerospike.EXP_PATH_SELECT_NO_FAIL)]
(key, meta, bins) = client.operate(key, ops)print(bins["catalog"])// OperationreadResult, err := client.Operate(nil, key, aero.SelectByPath("catalog", aero.EXP_PATH_SELECT_MAP_KEY | aero.EXP_PATH_SELECT_NO_FAIL aero.CtxAllChildren(), aero.CtxAllChildrenWithFilter(filterOnFeatured), aero.CtxMapKey(aero.NewValue("variants")), aero.CtxAllChildrenWithFilter(filterOnVariantInventory), ),)fmt.Println(readResult.Bins["catalog"])// Details elided for brevityas_exp_build(filter_on_featured, ...);as_exp_build(filter_on_variant_inventory, ...);
// Operationas_cdt_ctx ctx;as_cdt_ctx_inita(&ctx, 4);as_cdt_ctx_add_all_children(&ctx);as_cdt_ctx_add_all_children_with_filter(&ctx, filter_on_featured);as_cdt_ctx_add_map_key(&ctx, (as_val*)as_string_new("variants", false));as_cdt_ctx_add_all_children_with_filter(&ctx, filter_on_variant_inventory);
as_operations ops;as_operations_inita(&ops, 1);status = as_operations_select_by_path(&err, &ops, "catalog", &ctx, AS_EXP_PATH_SELECT_MAP_KEY | AS_EXP_PATH_SELECT_NO_FAIL);if (status != AEROSPIKE_OK) { goto fail_select_by_path;}
as_record* rec = NULL;status = aerospike_key_operate(&as, &err, NULL, &key, &ops, &rec);if (status != AEROSPIKE_OK) { goto fail_key_operate;}
// Print in JSON format
as_map* map = as_record_get_map(rec, "catalog");if (map) { char* map_str = as_val_tostring((as_val*)map); log("%s\n", map_str); free(map_str);} else { log("No data returned\n");}// OperationRecord record = client.Operate(null, key, CDTOperation.SelectByPath("catalog", SelectFlag.MAP_KEY | SelectFlag.NO_FAIL, CTX.AllChildren(), // dive into all products CTX.AllChildrenWithFilter(filterOnFeatured), // only featured products CTX.MapKey(Value.Get("variants")), // dive into variants CTX.AllChildrenWithFilter(filterOnVariantInventory) // only in-stock variants ));Console.WriteLine(System.Text.Json.JsonSerializer.Serialize((Dictionary<object, object>)record.GetList("catalog"), new System.Text.Json.JsonSerializerOptions { WriteIndented = true }));const context = new Context() // Create CDT Context
context.addAllChildren()context.addMapKey('variants') // only 'variants' instancescontext.addAllChildrenWithFilter(filterOnCheapInStock) // only in-stock
console.log(exp.pathSelectFlags.MAP_KEY)
// Operationconst ops = [ op.selectByPath("catalog", exp.pathSelectFlags.MATCHING_TREE, context)]
const result = await client.operate(key, ops)
console.log(result.bins)Expected output:
["2001","2003"]✅ Only the keys from SKU 10000001, Classic T-Shirt are returned.
⚠️ Item 50000009, Smart TV, has list-backed variants, so there are no map keys to return.
Modify nested elements with modifyByPath
You can update selected values in place.
Example: Increase quantity by 10 for all in-stock variants of featured products.
// Increment quantity by 10 and return the modified mapExpression incrementQuantity = Exp.build( MapExp.put( MapPolicy.Default, Exp.val("quantity"), // key to update Exp.add( // new value: current quantity + 10 MapExp.getByKey(MapReturnType.VALUE, Exp.Type.INT, Exp.val("quantity"), Exp.mapLoopVar(LoopVarPart.VALUE)), Exp.val(10) ), Exp.mapLoopVar(LoopVarPart.VALUE) // map to update ));
client.operate(null, key, CdtOperation.modifyByPath("catalog", Exp.MODIFY_DEFAULT, incrementQuantity, CTX.allChildren(), CTX.allChildrenWithFilter(filterOnFeatured), CTX.mapKey(Value.get("variants")), CTX.allChildrenWithFilter(filterOnVariantInventory) ));
Record readResult = client.get(null, key);
System.out.println(readResult.getList("catalog"));add_exp = exp.Add( exp.MapGetByKey( ctx=None, return_type=MAP_RETURN_VALUE, value_type=exp.ResultType.INTEGER, key=exp.Val("quantity"), bin=exp.LoopVarMap(aerospike.EXP_LOOPVAR_VALUE) ), exp.Val(10))
# Increment quantity by 10 and return the modified mapincrement_quantity = exp.MapPut( ctx=None, policy=None, key="quantity", value=add_exp, bin=exp.LoopVarMap(aerospike.EXP_LOOPVAR_VALUE)).compile()
ops = [ operations.modify_by_path( "catalog", [ cdt_ctx.cdt_ctx_all_children(), cdt_ctx.cdt_ctx_all_children_with_filter(filter_on_featured), cdt_ctx.cdt_ctx_map_key('variants'), cdt_ctx.cdt_ctx_all_children_with_filter(filter_on_variant_inventory) ], increment_quantity, aerospike.EXP_PATH_MODIFY_DEFAULT)]
client.operate(key, ops)
(key, meta, bins) = client.get(key)print(json.dumps(bins["catalog"], indent=4))// Increment quantity by 10 and return the modified mapincrementQuantity := aero.ExpMapPut( aero.DefaultMapPolicy(), aero.ExpStringVal("quantity"), aero.ExpNumAdd( aero.ExpMapGetByKey( aero.MapReturnType.VALUE, aero.ExpTypeINT, aero.ExpStringVal("quantity"), aero.ExpMapLoopVar(aero.VALUE), ), aero.ExpIntVal(10), ), aero.ExpMapLoopVar(aero.VALUE),)
_, err = client.Operate(nil, key, aero.ModifyByPath("catalog", aero.EXP_PATH_MODIFY_DEFAULT, incrementQuantity, aero.CtxAllChildren(), aero.CtxAllChildrenWithFilter(filterOnFeatured), aero.CtxMapKey(aero.NewValue("variants")), aero.CtxAllChildrenWithFilter(filterOnVariantInventory), ),)
record, _ := client.Get(nil, key)fmt.Println(record.Bins["catalog"])// Configure our increment operation// Increment quantity by 10 and return the modified mapas_exp_build(increment_quantity, as_exp_map_put( NULL, NULL, as_exp_str("quantity"), as_exp_add( as_exp_map_get_by_key( NULL, AS_MAP_RETURN_VALUE, AS_EXP_TYPE_INT, as_exp_str("quantity"), as_exp_loopvar_map(AS_EXP_LOOPVAR_MAP_VALUE) ), as_exp_int64(10) ), as_exp_str("catalog")));if (increment_quantity == NULL) { goto fail_increment_quantity;}
// Details elided for brevityas_exp_build(filter_on_featured, ...);as_exp_build(filter_on_variant_inventory, ...);
// Operation
as_cdt_ctx ctx;as_cdt_ctx_inita(&ctx, 4);as_cdt_ctx_add_all_children(&ctx),as_cdt_ctx_add_all_children_with_filter(&ctx, filter_on_featured);as_cdt_ctx_add_map_key(&ctx, as_exp_str("variants")),as_cdt_ctx_add_all_children_with_filter(&ctx, filter_on_variant_inventory);
as_operations ops;as_operations_inita(&ops, 1);status = as_operations_modify_by_path(&err, &ops, "catalog", &ctx, increment_quantity, AS_EXP_PATH_MODIFY_DEFAULT);if (status != AEROSPIKE_OK) { goto fail_select_by_path;}
as_record* rec = NULL;status = aerospike_key_operate(&as, &err, NULL, &key, &ops, &rec);if (status != AEROSPIKE_OK) { goto fail_key_operate;}
status = aerospike_key_get(&as, &err, NULL, &key, &rec);if (status != AEROSPIKE_OK) { goto fail_key_get;}
as_map* map = as_record_get_map(rec, "catalog");if (map) { char* map_str = as_val_tostring((as_val*)map); log("%s\n", map_str); free(map_str);} else { log("No data returned\n");}// Increment quantity by 10 and return the modified mapExp incrementExp = MapExp.Put( MapPolicy.Default, Exp.Val("quantity"), Exp.Add( MapExp.GetByKey(MapReturnType.VALUE, Exp.Type.INT, Exp.Val("quantity"), Exp.MapLoopVar(LoopVarPart.VALUE)), Exp.Val(10) ), Exp.MapLoopVar(LoopVarPart.VALUE));
Expression modifyExpression = Exp.Build(incrementExp);
// Write the modified map to a new binRecord record = client.Operate(null, key, CDTOperation.ModifyByPath("catalog", ModifyFlag.DEFAULT, modifyExpression, CTX.AllChildren(), // dive into all products CTX.AllChildrenWithFilter(filterOnFeatured), // only featured products CTX.MapKey(Value.Get("variants")), // dive into variants CTX.AllChildrenWithFilter(filterOnVariantInventory) // only in-stock variants ));
// Read back the updated recordRecord updatedRecord = client.Get(null, key);Console.WriteLine(System.Text.Json.JsonSerializer.Serialize((Dictionary<object, object>)updatedRecord.GetValue("catalog"), new System.Text.Json.JsonSerializerOptions { WriteIndented = true }));const context = new Context()
context.addAllChildren()context.addAllChildrenWithFilter(filterOnFeatured)context.addMapKey('variants')context.addAllChildrenWithFilter(filterOnVariantInventory)
// Operationconst ops = [ op.modifyByPath("catalog", incrementQuantity, exp.pathModifyFlags.DEFAULT, context)]
await client.operate(key, ops)
const result = await client.get(key)
console.log(result.bins.catalog)Expected Record Modification (diff excerpt):
{ "inventory": { "10000001": { "category": "clothing", "featured": true, "name": "Classic T-Shirt", "description": "A lightweight cotton T-shirt perfect for everyday wear.", "variants": { "2001": { "size": "S", "price": 25, "quantity": 110 }, // 100 -> 110 "2003": { "size": "L", "price": 27, "quantity": 60 } // 50 -> 60 } }, "50000009": { "category": "electronics", "featured": true, "name": "Smart TV", "description": "Ultra HD smart television with built-in streaming apps.", "variants": [ { "sku": 3007, "spec": "1080p", "price": 199, "quantity": 70 }, // 60 -> 70 { "sku": 3008, "spec": "4K", "price": 399, "quantity": 40 } // 30 -> 40 ] }, }}✅ Inventories for in-stock variants are incremented directly on the server.
Combine multiple filters
Filters can be chained with AND / OR with each expression pulling data from the current iteration’s element into a different loop variable.
Example: Select variants that are in stock and have price < 50.
Exp filterOnCheapInStock = Exp.and( Exp.gt( MapExp.getByKey(MapReturnType.VALUE, Exp.Type.INT, Exp.val("quantity"), Exp.mapLoopVar(LoopVarPart.VALUE)), Exp.val(0)), Exp.lt( MapExp.getByKey(MapReturnType.VALUE, Exp.Type.INT, Exp.val("price"), Exp.mapLoopVar(LoopVarPart.VALUE)), Exp.val(50)));// OperationRecord record = client.operate(null, key, CdtOperation.selectByPath("catalog", Exp.SELECT_MATCHING_TREE, CTX.allChildren(), CTX.allChildrenWithFilter(filterOnFeatured), CTX.mapKey(Value.get("variants")), CTX.allChildrenWithFilter(filterOnCheapInStock)));
System.out.println(record.getList("catalog"));filter_on_cheap_in_stock = exp.And( exp.GT( exp.MapGetByKey( ctx=None, return_type=MAP_RETURN_VALUE, value_type=exp.ResultType.INTEGER, key=exp.Val("quantity"), bin=exp.LoopVarMap(aerospike.EXP_LOOPVAR_VALUE) ), exp.Val(0) ), exp.LT( exp.MapGetByKey( ctx=None, return_type=MAP_RETURN_VALUE, value_type=exp.ResultType.INTEGER, key=exp.Val("price"), bin=exp.LoopVarMap(aerospike.EXP_LOOPVAR_VALUE) ), exp.Val(50) )).compile()
# Operationops = [ operations.select_by_path( "catalog", [ cdt_ctx.cdt_ctx_all_children(), cdt_ctx.cdt_ctx_all_children_with_filter(filter_on_featured), cdt_ctx.cdt_ctx_map_key("variants"), cdt_ctx.cdt_ctx_all_children_with_filter(filter_on_cheap_in_stock) ], aerospike.EXP_PATH_SELECT_MATCHING_TREE)](key, meta, bins) = client.operate(key, ops)print(bins["catalog"])filterOnCheapInStock := aero.ExpAnd( aero.ExpGreater( aero.ExpMapGetByKey( aero.MapReturnType.VALUE, aero.ExpTypeINT, aero.ExpStringVal("quantity"), aero.ExpMapLoopVar(aero.VALUE), ), aero.ExpIntVal(0), ), aero.ExpLess( aero.ExpMapGetByKey( aero.MapReturnType.VALUE, aero.ExpTypeINT, aero.ExpStringVal("price"), aero.ExpMapLoopVar(aero.VALUE), ), aero.ExpIntVal(50), ),)// OperationcheapInStock, err := client.Operate(nil, key, aero.SelectByPath("catalog", aero.EXP_PATH_SELECT_MATCHING_TREE, aero.CtxAllChildren(), aero.CtxAllChildrenWithFilter(filterOnFeatured), aero.CtxMapKey(aero.NewValue("variants")), aero.CtxAllChildrenWithFilter(filterOnCheapInStock), ),)fmt.Println(cheapInStock.Bins["catalog"])as_exp_build(filter_on_cheap_in_stock, as_exp_and( as_exp_cmp_gt( as_exp_map_get_by_key( NULL, AS_MAP_RETURN_VALUE, AS_EXP_TYPE_INT, as_exp_str("quantity"), as_exp_loopvar_map(AS_EXP_LOOPVAR_MAP_VALUE) ), as_exp_int64(0) ), as_exp_cmp_lt( as_exp_map_get_by_key( NULL, AS_MAP_RETURN_VALUE, AS_EXP_TYPE_INT, as_exp_str("price"), as_exp_loopvar_map(AS_EXP_LOOPVAR_MAP_VALUE) ), as_exp_int64(50) )));if (filter_on_cheap_in_stock == NULL) { goto fail_filter_on_cheap_in_stock;}
// Operation
as_cdt_ctx ctx;as_cdt_ctx_inita(&ctx, 4);as_cdt_ctx_add_all_children(&ctx),as_cdt_ctx_add_all_children_with_filter(&ctx, filter_on_featured);as_cdt_ctx_add_map_key(&ctx, as_exp_str("variants"));as_cdt_ctx_add_all_children_with_filter(&ctx, filter_on_cheap_in_stock);
as_operations ops;as_operations_inita(&ops, 1);status = as_operations_select_by_path(&err, &ops, "catalog", &ctx, AS_EXP_PATH_SELECT_MATCHING_TREE);if (status != AEROSPIKE_OK) { goto fail_select_by_path;}
as_record* rec = NULL;status = aerospike_key_operate(&as, &err, NULL, &key, &ops, &rec);if (status != AEROSPIKE_OK) { goto fail_key_operate;}
// Print in JSON format
as_map* map = as_record_get_map(rec, "catalog");if (map) { char* map_str = as_val_tostring((as_val*)map); log("%s\n", map_str); free(map_str);} else { log("No data returned\n");}Exp filterOnCheapInStock = Exp.And( Exp.GT( MapExp.GetByKey(MapReturnType.VALUE, Exp.Type.INT, Exp.Val("quantity"), Exp.MapLoopVar(LoopVarPart.VALUE) ), Exp.Val(0) ), Exp.LT( MapExp.GetByKey(MapReturnType.VALUE, Exp.Type.INT, Exp.Val("price"), Exp.MapLoopVar(LoopVarPart.VALUE) ), Exp.Val(50) ));
// OperationRecord record = client.Operate(null, key, CDTOperation.SelectByPath("catalog", SelectFlag.MATCHING_TREE, CTX.AllChildren(), CTX.AllChildrenWithFilter(filterOnFeatured), CTX.MapKey(Value.Get("variants")), CTX.AllChildrenWithFilter(filterOnCheapInStock) ));
Console.WriteLine(System.Text.Json.JsonSerializer.Serialize((Dictionary<object, object>)record.GetMap("catalog"), new System.Text.Json.JsonSerializerOptions { WriteIndented = true }));const filterOnCheapInStock = exp.and( exp.gt( exp.maps.getByKey( exp.loopVarMap(exp.loopVarPart.VALUE), // the value of the element in this iteration is extracted into a loop variable whose data type is a map exp.str('quantity'), exp.type.INT, maps.returnType.VALUE ), exp.int(0) ), exp.lt( exp.maps.getByKey( exp.loopVarMap(exp.loopVarPart.VALUE), // the value of the element in this iteration is extracted into a loop variable whose data type is a map exp.str('price'), exp.type.INT, maps.returnType.VALUE ), exp.int(50) ))
const context = new Context()
context.addAllChildren()context.addAllChildrenWithFilter(filterOnFeatured)
context.addMapKey('variants')context.addAllChildrenWithFilter(filterOnCheapInStock)
// Operationconst ops = [ op.selectByPath("catalog", exp.pathSelectFlags.MATCHING_TREE, context)]
const result = await client.operate(key, ops)
console.log(result.bins.catalog)Expected output:
{ "inventory": { "10000001": { "variants": { "2001": { "price": 25, "quantity": 100, "size": "S" }, "2003": { "price": 27, "quantity": 50, "size": "L" } } }, "50000006": { "variants": {} }, "50000009": { "variants": {} } }}✅ Only items are returned which have price < 50 and quantity > 0.
❌ Item 10000002, Casual Polo Shirt, excluded (featured=false).
❌ Item 50000006, Laptop Pro 14, excluded (quantity=0).
❌ Item 50000009, Smart TV, both variants excluded (price > 50).
NO_FAIL: tolerate malformed product
If we add this item to the inventory bin:
"10000003": { "category": "clothing", "featured": true, "name": "Hooded Sweatshirt", "description": "Warm fleece hoodie with front pocket and adjustable hood.", "variants": "no variant"}The dataset now includes item 10000003 with variants: “no variant” (a string).
Any traversal that reaches variants and then tries to treat it as a
Map/List will hit a type mismatch and throw an error unless SelectFlags.NO_FAIL.flag is set.
// OperationRecord noFailResponse = client.operate(null, key, CdtOperation.selectByPath("catalog", Exp.SELECT_MAP_KEY | Exp.SELECT_NO_FAIL, CTX.allChildren(), CTX.allChildrenWithFilter(filterOnFeatured), CTX.mapKey(Value.get("variants")), CTX.allChildrenWithFilter(filterOnVariantInventory) ));System.out.println(noFailResponse.getList("catalog"));# Operationops = [ operations.select_by_path( "catalog", [ cdt_ctx.cdt_ctx_all_children(), cdt_ctx.cdt_ctx_all_children_with_filter(filter_on_featured), cdt_ctx.cdt_ctx_map_key("variants"), cdt_ctx.cdt_ctx_all_children_with_filter(filter_on_variant_inventory) ], aerospike.EXP_PATH_SELECT_MAP_KEY | aerospike.EXP_PATH_SELECT_NO_FAIL)](key, meta, bins) = client.operate(key, ops)print(bins["catalog"])// Operationrecord, _ := client.Operate(nil, key, aero.SelectByPath("catalog", aero.EXP_PATH_SELECT_MAP_KEY | aero.EXP_PATH_SELECT_NO_FAIL, aero.CtxAllChildren(), aero.CtxAllChildrenWithFilter(filterOnFeatured), aero.CtxMapKey(aero.NewValue("variants")), aero.CtxAllChildrenWithFilter(filterOnVariantInventory), ),)fmt.Println(record.Bins["catalog"])as_exp_build(filter_on_featured, ...);as_exp_build(filter_on_variant_inventory, ...);
// Operationas_cdt_ctx ctx;as_cdt_ctx_inita(&ctx, 4);as_cdt_ctx_add_all_children(&ctx);as_cdt_ctx_add_all_children_with_filter(&ctx, filter_on_featured);as_cdt_ctx_add_map_key(&ctx, (as_val*)as_string_new("variants", false));as_cdt_ctx_add_all_children_with_filter(&ctx, filter_on_variant_inventory);
as_operations ops;as_operations_inita(&ops, 1);status = as_operations_select_by_path(&err, &ops, "catalog", &ctx, AS_EXP_PATH_SELECT_MAP_KEY | AS_EXP_PATH_SELECT_NO_FAIL);if (status != AEROSPIKE_OK) { goto fail_select_by_path;}
as_record* rec = NULL;status = aerospike_key_operate(&as, &err, NULL, &key, &ops, &rec);if (status != AEROSPIKE_OK) { goto fail_key_operate;}
// Print in JSON format
as_map* map = as_record_get_map(rec, "catalog");if (map) { char* map_str = as_val_tostring((as_val*)map); log("%s\n", map_str); free(map_str);} else { log("No data returned\n");}or
as_exp_build(filter_on_featured, ...);as_exp_build(filter_on_variant_inventory, ...);
// Operationas_cdt_ctx ctx;as_cdt_ctx_inita(&ctx, 4);as_cdt_ctx_add_all_children(&ctx);as_cdt_ctx_add_all_children_with_filter(&ctx, filter_on_featured);as_cdt_ctx_add_map_key(&ctx, (as_val*)as_string_new("variants", false));as_cdt_ctx_add_all_children_with_filter(&ctx, filter_on_variant_inventory);
as_operations ops;as_operations_inita(&ops, 1);status = as_operations_modify_by_path(&err, &ops, "catalog", &ctx, increment_quantity, AS_EXP_PATH_MODIFY_DEFAULT | AS_EXP_PATH_MODIFY_NO_FAIL);if (status != AEROSPIKE_OK) { goto fail_select_by_path;}
as_record* rec = NULL;status = aerospike_key_operate(&as, &err, NULL, &key, &ops, &rec);if (status != AEROSPIKE_OK) { goto fail_key_operate;}
status = aerospike_key_get(&as, &err, NULL, &key, &rec);if (status != AEROSPIKE_OK) { goto fail_key_get;}
// Print in JSON format
as_map* map = as_record_get_map(rec, "catalog");if (map) { char* map_str = as_val_tostring((as_val*)map); log("%s\n", map_str); free(map_str);} else { log("No data returned\n");}// OperationRecord noFailResponse = client.Operate(null, key, CDTOperation.SelectByPath("catalog", SelectFlag.MAP_KEY | SelectFlag.NO_FAIL, CTX.AllChildren(), CTX.AllChildrenWithFilter(filterOnFeatured), CTX.MapKey(Value.Get("variants")), CTX.AllChildrenWithFilter(filterOnVariantInventory) ));Console.WriteLine(System.Text.Json.JsonSerializer.Serialize((Dictionary<object, object>)noFailResponse.GetList("catalog"), new System.Text.Json.JsonSerializerOptions { WriteIndented = true }));const context = new Context()
context.addAllChildren()context.addAllChildrenWithFilter(filterOnFeatured)context.addMapKey('variants')context.addAllChildrenWithFilter(filterOnVariantInventory)
// Operationconst ops = [ op.selectByPath("catalog", exp.pathSelectFlags.MAP_KEY | exp.pathSelectFlags.NO_FAIL, context)]
const result = await client.operate(key, ops)
console.log(result.bins.catalog)-
malformed_product.variantsis “no variant”. -
With
NO_FAIL,malformed_productis excluded silently because variants was “no variant”.
Expected output:
Same as the corresponding non-NO_FAIL query, omitting any items from malformed_product.
["2001","2003"]❌ Item 10000003 skipped silently because variants was a string.
Handle errors gracefully
Path Expression operations can fail for several reasons. Always wrap operations in error handling to provide a good user experience.
Common error scenarios:
- Target bin doesn’t exist or isn’t a CDT
- Type mismatch in filter expression (without
NO_FAIL) - Server timeout during complex traversals
import com.aerospike.client.AerospikeException;import com.aerospike.client.ResultCode;
try { Record record = client.operate(null, key, CdtOperation.selectByPath("catalog", Exp.SELECT_MATCHING_TREE, CTX.allChildren(), CTX.allChildrenWithFilter(filterOnFeatured), CTX.mapKey(Value.get("variants")), CTX.allChildrenWithFilter(filterOnVariantInventory))); // Success - process the filtered results System.out.println(record.getList("catalog"));} catch (AerospikeException e) { switch (e.getResultCode()) { case ResultCode.BIN_TYPE_ERROR: case ResultCode.OP_NOT_APPLICABLE: // The bin exists but isn't a Map or List - can't traverse it System.err.println("Bin is not a Map or List"); break; case ResultCode.PARAMETER_ERROR: // The filter expression is malformed or uses wrong types System.err.println("Invalid expression in filter"); break; default: // Unexpected error (network, timeout, etc.) - propagate it throw e; }}import aerospikefrom aerospike import exception as aero_exception
ops = [ operations.select_by_path( "catalog", [ cdt_ctx.cdt_ctx_all_children(), cdt_ctx.cdt_ctx_all_children_with_filter(filter_on_featured), cdt_ctx.cdt_ctx_map_key('variants'), cdt_ctx.cdt_ctx_all_children_with_filter(filter_on_variant_inventory) ], aerospike.EXP_PATH_SELECT_MAP_KEY | aerospike.EXP_PATH_SELECT_NO_FAIL)]try: # Execute the path expression operation (key, meta, bins) = client.operate(key, ops) # Success - process the filtered results print(bins["catalog"])
except aero_exception.OpNotApplicable as e: # The bin exists but isn't a Map or List - can't traverse it print(f"Bin is not a Map or List: {e}")
except aero_exception.BinIncompatibleType as e: # The bin exists but isn't a Map or List - can't traverse it print(f"Bin is not a Map or List: {e}")
except aero_exception.InvalidRequest as e: # The filter expression is malformed or uses wrong types print(f"Invalid expression in filter: {e}")
except aero_exception.AerospikeError as e: # Unexpected error (network, timeout, etc.) - propagate it raise// Execute the path expression operation
record, err = client.Operate(nil, key, aero.SelectByPath("catalog", aero.EXP_PATH_SELECT_MATCHING_TREE, aero.CtxAllChildren(), aero.CtxAllChildrenWithFilter(filterOnFeatured), aero.CtxMapKey(aero.NewValue("variants")), aero.CtxAllChildrenWithFilter(filterOnVariantInventory), ),)
// Check for errors and handle specific casesif err != nil { // Type assert to access Aerospike-specific error details if aeroErr, ok := err.(*aero.AerospikeError); ok { switch aeroErr.ResultCode { case types.BIN_TYPE_ERROR: case types.OP_NOT_APPLICABLE: // The bin exists but isn't a Map or List - can't traverse it log.Println("Bin is not a Map or List") case types.PARAMETER_ERROR: // The filter expression is malformed or uses wrong types log.Println("Invalid expression in filter") default: // Unexpected error (network, timeout, etc.) log.Fatal(aeroErr) } }}
// Success - process the filtered resultsfmt.Println(record.Bins["catalog"])// ... setup elided for brevity ...as_cdt_ctx ctx;as_cdt_ctx_inita(&ctx, 4);as_cdt_ctx_add_all_children(&ctx);as_cdt_ctx_add_all_children_with_filter(&ctx, filter_on_featured);as_cdt_ctx_add_map_key(&ctx, (as_val*)as_string_new("variants", false));as_cdt_ctx_add_all_children_with_filter(&ctx, filter_on_variant_inventory);
as_operations ops;as_operations_inita(&ops, 1);status = as_operations_select_by_path(&err, &ops, "catalog", &ctx, AS_EXP_PATH_SELECT_MATCHING_TREE);if (status != AEROSPIKE_OK) { goto fail_key_operate;}
as_record* rec = NULL;status = aerospike_key_operate(&as, &err, NULL, &key, &ops, &rec);if (status != AEROSPIKE_OK) { // if-then-switch is commonly used to avoid delays in hot-path // code, as different compilers will likely optimize switch statements // to varying degrees, especially depending upon how sparse the cases // are. This way, switch overhead is incurred only when an error is // known to have occurred. switch (status) { case AEROSPIKE_ERR_BIN_INCOMPATIBLE_TYPE: case AEROSPIKE_ERR_OP_NOT_APPLICABLE: // The bin exists but isn't a Map or List; cannot traverse it. fprintf(stderr, "Bin is not a Map or List"); break; case AEROSPIKE_ERR_PARAMETER_ERROR: // The filter expression is malformed or uses wrong types fprintf(stderr, "Invalid expression in filter"); break;
default: // Unknown error (network, timeout, etc.) // // Note that the status is also available within the as_error // structure, as member code. fprintf(stderr, "Unknown error: code %d\n" " msg %s\n", err.code, err.message ); break; }}else{ // Success - process the filtered results // Print in JSON format as_map* map = as_record_get_map(rec, "catalog"); if (map) { char* map_str = as_val_tostring((as_val*)map); log("%s\n", map_str); free(map_str); } else { log("No data returned\n"); }}try{ Record record = client.Operate(null, key, CDTOperation.SelectByPath( "catalog", SelectFlag.MATCHING_TREE, CTX.AllChildren(), CTX.AllChildrenWithFilter(filterOnFeatured), CTX.MapKey(Value.Get("variants")), CTX.AllChildrenWithFilter(filterOnVariantInventory) ) );
// Success - process the filtered results Console.WriteLine(System.Text.Json.JsonSerializer.Serialize((Dictionary<object, object>)record.GetMap("catalog"), new System.Text.Json.JsonSerializerOptions { WriteIndented = true }));}catch (AerospikeException e){ switch (e.Result) { case ResultCode.BIN_TYPE_ERROR: case ResultCode.OP_NOT_APPLICABLE: // The bin exists but isn't a Map or List - can't traverse it Console.WriteLine("Bin is not a Map or List"); break; case ResultCode.PARAMETER_ERROR: // The filter expression is malformed or uses wrong types Console.WriteLine("Invalid expression in filter"); break;
default: // Unexpected error (network, timeout, etc.) - propagate it throw; }}const context = new Context()
context.addAllChildren()context.addAllChildrenWithFilter(filterOnFeatured)context.addMapKey('variants')context.addAllChildrenWithFilter(filterOnVariantInventory)
console.log(exp.pathSelectFlags.MAP_KEY)
// Operationconst ops = [ op.selectByPath("catalog", exp.pathSelectFlags.MAP_KEY, context)]
try { // Execute the path expression operation const result = await client.operate(key, ops)
// Success - process the filtered results console.log(result.bins.catalog)
} catch (err) { if (err.code === Aerospike.status.ERR_BIN_INCOMPATIBLE_TYPE) { // The bin exists but isn't a Map or List - can't traverse it console.error(`Bin is not a Map or List: ${err.message}`)
} else if (err.code === Aerospike.status.ERR_REQUEST_INVALID) { // The filter expression is malformed or uses wrong types console.error(`Invalid expression in filter: ${err.message}`)
} else if (err instanceof Aerospike.AerospikeError) { // Unexpected error (network, timeout, etc.) - propagate it throw err
} else { // Non-Aerospike error throw err }}