Skip to content

Path expressions usage examples

For the complete documentation index see: llms.txt

All documentation pages available in markdown.

This page contains examples of using path expressions to select elements from a document modeled in Aerospike as nested map and list structures.

Each operation’s Example shows the code in nine tabs: Aerospike Expression Language (AEL) text on the Java SDK and Python SDK tabs, and the Exp builder on the other seven. See the AEL reference for AEL grammar.

The quickstart guide covers a common use case: filtering and selecting products and their in-stock variants. This section highlights additional capabilities supported by path expressions.

Accessing current element data from a map key, list index or element value with a LoopVar

When using a path expression to match Map or List elements, you can assign data from the matched element to loop variables.

Example: Select only products whose key starts with SKU 1000.

Record record = session.query(key)
.bin("catalog")
.selectFrom("$.catalog.inventory.*[?(@key =~ /1000.*/)].getTree()")
.execute()
.getFirstRecord();
System.out.println(record.getMap("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.

NO_FAIL is included here because variants is mixed in this dataset: some products store variants as a map, while others store variants as a list. Since MAP_KEY only applies to map-backed branches, NO_FAIL skips incompatible branches instead of failing the whole operation.

// Product-level filter: featured == true
Exp filterOnFeatured = Exp.eq(
MapExp.getByKey(MapReturnType.VALUE, Exp.Type.BOOL,
Exp.val("featured"), Exp.mapLoopVar(LoopVarPart.VALUE)),
Exp.val(true));
// Variant-level filter: quantity > 0
Exp filterOnVariantInventory = Exp.gt(
MapExp.getByKey(MapReturnType.VALUE, Exp.Type.INT,
Exp.val("quantity"), Exp.mapLoopVar(LoopVarPart.VALUE)),
Exp.val(0));
// AEL takes no NO_FAIL on a read, so this path uses the builder.
Record readResult = session.query(key)
.bin("catalog")
.onEachChild()
.onEachChild(filterOnFeatured)
.onMapKey("variants")
.onEachChild(filterOnVariantInventory)
.collectKeys(opts -> opts.noFail(true))
.execute()
.getFirstRecord();
System.out.println(readResult.getList("catalog"));

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
session.update(key)
.bin("catalog")
.upsertFrom("$.catalog.inventory.*[?(@.featured == true)]"
+ ".variants.*[?(@.quantity > 0)].quantity.modify(@ + 10)")
.execute();
Record readResult = session.query(key).execute().getFirstRecord();
System.out.println(readResult.getMap("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.

Remove elements with removeResult

Use removeResult with modifyByPath to delete elements selected by the path context.

  • If the path/filter matches one element, one element is removed.
  • If the path/filter matches multiple elements, all matches are removed.

Example: Remove all out-of-stock variants (quantity == 0) from featured products.

// Remove each variant where quantity == 0.
session.update(key)
.bin("catalog")
.upsertFrom("$.catalog.inventory.*[?(@.featured == true)]"
+ ".variants.*[?(@.quantity == 0)].remove():NO_FAIL")
.execute();

Expected record modification (excerpt):

{
"inventory": {
"10000001": {
"variants": {
"2001": { "size": "S", "price": 25, "quantity": 100 },
"2003": { "size": "L", "price": 27, "quantity": 50 }
}
},
"50000009": {
"variants": [
{ "sku": 3007, "spec": "1080p", "price": 199, "quantity": 60 },
{ "sku": 3008, "spec": "4K", "price": 399, "quantity": 30 }
]
},
"50000006": { "variants": {} }
}
}

✅ Out-of-stock entries are removed from matching map/list branches.

Combine multiple filters

Filters can be chained with AND / OR with each expression pulling data from the current matched element into a different loop variable.

Example: Select variants that are in stock and have price < 50.

Record record = session.query(key)
.bin("catalog")
.selectFrom("$.catalog.inventory.*[?(@.featured == true)]"
+ ".variants.*[?(@.quantity > 0 and @.price < 50)].getTree()")
.execute()
.getFirstRecord();
System.out.println(record.getMap("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 variants with price < 50 and quantity > 0 are returned.
  • ❌ Item 10000002, Casual Polo Shirt, excluded (featured=false).
  • ❌ Variant 3001 excluded from item 50000006, Laptop Pro 14 (quantity=0). The item is featured, so it stays, with an empty variants map.
  • ❌ 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 is set.

// Product-level filter: featured == true
Exp filterOnFeatured = Exp.eq(
MapExp.getByKey(MapReturnType.VALUE, Exp.Type.BOOL,
Exp.val("featured"), Exp.mapLoopVar(LoopVarPart.VALUE)),
Exp.val(true));
// Variant-level filter: quantity > 0
Exp filterOnVariantInventory = Exp.gt(
MapExp.getByKey(MapReturnType.VALUE, Exp.Type.INT,
Exp.val("quantity"), Exp.mapLoopVar(LoopVarPart.VALUE)),
Exp.val(0));
// AEL takes no NO_FAIL on a read, so this path uses the builder.
Record noFailResponse = session.query(key)
.bin("catalog")
.onEachChild()
.onEachChild(filterOnFeatured)
.onMapKey("variants")
.onEachChild(filterOnVariantInventory)
.collectKeys(opts -> opts.noFail(true))
.execute()
.getFirstRecord();
System.out.println(noFailResponse.getList("catalog"));
  • 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.

["2001","2003"]
  • ❌ Item 10000003 skipped silently because variants was a string.

Remove nested elements with modifyByPath

You can remove selected elements in place by combining a path filter with a removeResult expression. The path navigates to and filters the target elements; removeResult expression tells the server to delete each match.

Example: Remove all size “M” variants across all products.

This example uses NO_FAIL because some products use list-backed variants or lack a "size" key entirely. Without NO_FAIL, the operation would fail on those products.

// Remove each size M variant.
session.update(key)
.bin("catalog")
.upsertFrom("$.catalog.inventory.*.variants.*[?(@.size == 'M')].remove():NO_FAIL")
.execute();
Record readResult = session.query(key).execute().getFirstRecord();
System.out.println(readResult.getMap("catalog"));

Expected Record Modification (diff excerpt):

{
"inventory": {
"10000001": {
"variants": {
"2001": { "size": "S", "price": 25, "quantity": 100 },
// "2002" (size M) removed
"2003": { "size": "L", "price": 27, "quantity": 50 }
}
},
"10000002": {
"variants": {
// "2004" (size M) removed
"2005": { "size": "XL", "price": 32, "quantity": 10 }
}
}
}
}
  • ✅ Variant "2002" (size M) removed from Classic T-Shirt.
  • ✅ Variant "2004" (size M) removed from Casual Polo Shirt.
  • ⚠️ NO_FAIL lets the operation skip electronics products that lack a "size" key or use list-backed variants.

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 isn’t a CDT (a bin that doesn’t exist returns no value, not an error)
  • Type mismatch in filter expression (without NO_FAIL)
  • Server timeout during complex traversals
try {
Record record = session.query(key)
.bin("catalog")
.selectFrom("$.catalog.inventory.*[?(@.featured == true)]"
+ ".variants.*[?(@.quantity > 0)].getTree()")
.execute()
.getFirstRecord();
// Success - process the filtered results
System.out.println(record.getMap("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;
}
}