Frequently asked questions
Q: What does the selectFlags parameter do, and what options are available?
A: The selectFlags parameter controls what the server returns from a path expression.
Possible values are:
| Value | Description |
|---|---|
MATCHING_TREE | Return a tree from the root (bin) level to the bottom of the tree, with only non-filtered out nodes. |
VALUE | Return a list of the values of the nodes finally selected by the context. |
MAP_KEY | For final selected nodes which are elements of maps, return the appropiate map key. |
MAP_KEY_VALUE | Return a list of key-value pairs. |
NO_FAIL | If the expression in the context hits an invalid type (e.g., selects as an integer when the value is a string), do not fail the operation, just ignore those elements. |
Q: Can I use path expressions on both Maps and Lists?
A: Yes. CTX.allChildren and CTX.allChildrenWithFilter work across both maps and lists.
Loop variables (MAP_KEY, VALUE, LIST_INDEX) allow filters to adapt depending on
whether the container is a map of entries or a list of elements.
Q: What kind of exception will I see on the client if I don’t use NO_FAIL? Is it recoverable or will the whole operation abort?
A: Without Exp.SELECT_NO_FAIL, if the server encounters a type mismatch
(e.g., it expects a map or list but finds a string), the entire path
expression operation fails. The operation does not return partial results.
Q: How do I return only certain pieces of data, such as only the variant IDs?
A: The SelectFlags parameter controls return modes. For example,
MATCHING_TREE returns the full subtree, MAP_KEY returns only keys, and VALUE
returns only values. Choose the mode that matches your use case.
Q: Can path expressions be combined with secondary indexes?
A: Yes. You can create expression-based indexes on filtered elements of Maps/Lists. This lets you query and traverse deeply nested structures without denormalizing data.
Q: Can I use an IN expression (for example, WHERE roomId IN (10001, 30002, 10003)) with path expressions?
A: Aerospike does not provide a generic SQL‑style IN operator at the cluster query level. However, within a single record, you can express IN‑style membership over map keys or values using expression primitives and loop variables.
Here is an example that filters only rooms whose map key (roomId) is in a given list of IDs:
// Build room-level filter: roomId IN roomIds AND notDeleted AND timeValidExp roomIdInListExp = Exp.gt( ListExp.getByValue( ListReturnType.COUNT, Exp.stringLoopVar(LoopVarPart.MAP_KEY), // current map key (roomId) Exp.val(roomIds) // list of allowed roomIds ), Exp.val(0) // > 0 -> membership);
Exp roomFilter = Exp.and(roomIdInListExp, notDeletedExp, timeValidExp);
// Use in a path expressionRecord record = client.operate(null, key, CdtOperation.selectByPath(binName, Exp.SELECT_NO_FAIL, CTX.allChildrenWithFilter(roomFilter), // room-level: roomId IN list + other filters CTX.allChildren(), CTX.allChildrenWithFilter(roomIdInListExp) ));// Build list of room IDs to checkas_arraylist room_ids;as_arraylist_init(&room_ids, N_ITEMS, N_ITEMS);
for (int i = 0; i < N_ITEMS; i++) { // call as_arraylist_append_str or as_arraylist_append_int64 // as required to build up list of room IDs.}
// Build room-level filter: roomId IN roomIds AND notDeleted AND timeValidas_exp_build(room_id_in_list, as_exp_cmp_gt( as_exp_list_get_by_value( NULL, AS_LIST_RETURN_COUNT, as_exp_loopvar_map(AS_EXP_LOOPVAR_KEY), room_ids ), as_exp_int64(0)));if (room_id_in_list == NULL) { goto fail_room_id_in_list;}
// Details omitted for brevity.as_exp_build(not_deleted, ...);as_exp_build(time_valid, ...);as_exp_build(beta_exp, ...);
as_exp_build(room_filter, as_exp_and( room_id_in_list, not_deleted, time_valid));if (room_filter == NULL) { goto fail_room_filter;}
as_cdt_ctx ctx;as_cdt_ctx_inita(&ctx, 3);as_cdt_ctx_add_all_children_with_filter(&ctx, room_filter); // room-level: roomId IN list + other filtersas_cdt_ctx_add_all_children(&ctx);as_cdt_ctx_add_all_children_with_filter(&ctx, beta_exp); // variant-level filter, e.g., beta > 0
as_operations ops;as_operations_inita(&ops, 1);status = as_operations_select_by_path(&err, &ops, bin_name, &ctx, AS_EXP_PATH_SELECT_MATCHING_TREE | 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;}// roomIdInListExp checks if roomId (map key) exists in the roomIds listroomIdInListExp := as.ExpGt( as.ExpListGetByValue( as.ListReturnTypeCount, // COUNT return type as.ExpStringLoopVar(as.MAP_KEY), // current map key (roomId) as.ExpListVal(roomIds), // list of allowed roomIds ), as.ExpIntVal(0), // > 0 -> membership)
// Combine with other filter expressionsroomFilter := as.ExpAnd(roomIdInListExp, notDeletedExp, timeValidExp)
// Perform the operation with SelectByPathrecord, err := client.Operate(nil, key, as.SelectByPath(binName, as.EXP_PATH_SELECT_NO_FAIL, as.CtxAllChildrenWithFilter(roomFilter), // room-level: roomId IN list + other filters as.CtxAllChildren(), // all children as.CtxAllChildrenWithFilter(roomIdInListExp), ),)Performance
Q: What are the performance implications of path expressions?
A: Path expressions execute server-side, which reduces network transfer by returning only matching elements. For deeply nested structures, this can significantly reduce latency compared to fetching entire records and filtering client-side.
Performance depends on:
- CDT size: Larger Maps/Lists require more processing time.
- Nesting depth: Deeper structures take longer to traverse.
- Filter complexity: Complex boolean expressions add overhead.
- Result size: Returning
MATCHING_TREEtransfers more data thanMAP_KEYS.
For performance-critical applications, benchmark with realistic data volumes.
Q: What’s the maximum nesting depth supported?
A: Path expressions support up to 15 levels of CDT nesting, matching the Aerospike CDT context depth limit.
Q: Are there limits on how many elements can be filtered?
A: There’s no hard limit on the number of elements, but very large CDTs (millions of elements) may impact latency. If you’re working with extremely large collections, consider partitioning data across multiple records or using secondary indexes to narrow the scope before applying path expressions.