Skip to content

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.*", 0, Exp.stringLoopVar(LoopVarPart.MAP_KEY));
// Operation
Record record = client.operate(null, key,
CdtOperation.selectByPath("inventory", Exp.SELECT_MATCHING_TREE,
CTX.allChildren(),
CTX.allChildrenWithFilter(filterOnKey)));
System.out.println(record.getList("inventory"));

Expected output:

{
"inventory": {
"10000001": { ... },
"10000002": { ... },
"10000003": { ... }
}
}

✅ 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.

Record readResult = client.operate(null, key,
CdtOperation.selectByPath(binName, Exp.SELECT_MATCHING_TREE,
CTX.allChildren(),
CTX.allChildrenWithFilter(filterOnFeatured),
CTX.mapKey(Value.get("variants")),
CTX.allChildrenWithFilter(filterOnVariantInventory)
)
);

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 modifyCdt

You can update selected values in place.

Example: Increase quantity by 10 for all in-stock variants of featured products.

Expression 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("inventory", Exp.SELECT_MATCHING_TREE, incrementQuantity,
CTX.allChildren(),
CTX.allChildrenWithFilter(filterOnFeatured),
CTX.mapKey(Value.get("variants")),
CTX.allChildrenWithFilter(filterOnVariantInventory)
)
);

Expected output (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)));
Record record = client.operate(null, key,
CdtOperation.selectByPath("inventory", Exp.SELECT_MATCHING_TREE,
CTX.allChildren(),
CTX.allChildren(),
CTX.mapKey(Value.get("variants")),
CTX.allChildrenWithFilter(filterOnCheapInStock)));

Expected output:

{
"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": 100 },
"2003": { "size": "L", "price": 27, "quantity": 50}
}
}
}
}

✅ 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.

Record noFailResponse = client.operate(null, key,
CdtOperation.selectByPath("inventory", Exp.SELECT_MATCHING_TREE | Exp.SELECT_NO_FAIL,
CTX.allChildren(),
CTX.allChildrenWithFilter(filterOnFeatured),
CTX.mapKey(Value.get("variants")),
CTX.allChildrenWithFilter(filterOnVariantInventory)
)
);
  • malformed_product.variants is “no variant”.

  • With NO_FAIL, malformed_product is excluded silently because variants was “no variant”.

Expected output:

Same as the corresponding non-NO_FAIL query, omitting any items from malformed_product.

{
"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": 100 },
"2003": { "size": "L", "price": 27, "quantity": 50
}
}
},
"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": 60 },
{ "sku": 3008, "spec": "4K", "price": 399, "quantity": 30 }
]
}
}
}

❌ 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 {
client.operate(null, key,
CdtOperation.selectByPath("inventory", Exp.SELECT_MATCHING_TREE,
CTX.allChildren(),
CTX.allChildrenWithFilter(filterOnFeatured),
CTX.mapKey(Value.get("variants")),
CTX.allChildrenWithFilter(filterOnVariantInventory)));
} catch (AerospikeException e) {
switch (e.getResultCode()) {
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;
}
}
Feedback

Was this page helpful?

What type of feedback are you giving?

What would you like us to know?

+Capture screenshot

Can we reach out to you?