Skip to content

Quickstart: path expressions

This page contains a quickstart guide for path expressions.

Path expressions enable granular indexing and querying from a nested map or list collection data type (CDT) using expressions.

Goals of the quickstart

The goal of the quickstart is to show you how to use path expressions to select elements from a document modeled in Aerospike as nested map and list structures. By the end, you’ll know how to filter products and their variants server-side and return only the relevant parts of the record, without denormalizing data or writing client-side processing in your application.

Data structure

For the purposes of this quickstart guide, we’ll use a simplified ecommerce product catalog stored as a single record in Aerospike. Products are modeled as a map and organized under a single inventory bin, keyed by product IDs (e.g. 10000001, 50000009).

Each product record includes:

  • category: product category (e.g. clothing, electronics)

  • featured: a boolean flag for merchandising purposes.

  • name and description: product metadata.

  • variants: either a map of SKUs to attributes (size/spec, price, quantity) or a list of variant objects.

This structure is similar to real-world product catalogs, in which a product may have multiple variants (sizes, colors, configurations), each with its own availability.

For this example app, the goal is to identify products to promote on the home page of an ecommerce website. We only want to select products that are featured and are in stock (have an quantity greater than 0).

Prerequisites

Project procedure

  1. Download the demo app.

    Use the following command to clone the app from GitHub:

    Terminal window
    git clone https://github.com/aerospike-examples/path-expressions-java-preview.git
  2. Start the Aerospike server in Docker.

    Terminal window
    cd path-expressions-java-preview
    docker compose -f container/docker-compose.yaml up -d

    Verify that the Aerospike server is running with the asadm command:

    Terminal window
    asadm

    Expected output similar to:

    Seed: [('127.0.0.1', 3000, None)]
    Config_file: /Users/dbuser/.aerospike/astools.conf, /etc/aerospike/astools.conf
    Aerospike Interactive Shell, version 2.12.0
    Found 1 nodes
    Online: 127.0.0.1:3000
    Admin>

    Exit asadm with the command exit.

  3. Build the application with Maven.

    Back at the shell command prompt, run the following command:

    Terminal window
    mvn clean install exec:java -Dexec.mainClass="com.aerospike.pathexpressions.PathExpressionsDemo"

    To use the Aerospike Java Client preview release, add the Aerospike Preview Repository to your build tool configuration and include the desired dependency.

  4. (Optional) Check your data with AQL.

    AQL is part of the Aerospike Tools package. It is a command-line tool for browsing data in an Aerospike database.

    To check your current data set with AQL, run the aql command and enter the following command at the AQL prompt:

    select inventory from test.products where PK='catalog'
  5. Explore the data set.

    The sample data set is named inventory_sample.json and is located in the data directory. It contains the following items:

    {
    "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 },
    "2002": { "size": "M", "price": 25, "quantity": 0 },
    "2003": { "size": "L", "price": 27, "quantity": 50 }
    }
    },
    "10000002": {
    "category": "clothing",
    "featured": false,
    "name": "Casual Polo Shirt",
    "description": "A soft polo shirt suitable for work or leisure.",
    "variants": {
    "2004": { "size": "M", "price": 30, "quantity": 20 },
    "2005": { "size": "XL", "price": 32, "quantity": 10 }
    }
    },
    "50000006": {
    "category": "electronics",
    "featured": true,
    "name": "Laptop Pro 14",
    "description": "High-performance laptop designed for professionals.",
    "variants": {
    "3001": { "spec": "8GB RAM", "price": 599, "quantity": 0 }
    }
    },
    "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 }
    ]
    }
    }
    }
  6. Define filters as expressions.

    The sample app filters at two levels of the data:

    • Product level: only include products where featured = true.

    • Variant level: only include variants where quantity > 0.

    Context stack: how filters apply

    When selecting elements with path expressions, the server evaluates filters at different depths. This example uses the following stack:

    inventory (bin)
    └── product (map entry, keyed by productId)
    ├── category
    ├── featured <-- product-level filter
    ├── name
    ├── description
    └── variants
    ├── { "2001": {...}, "2002": {...} } <-- map-backed variants
    └── [ {sku:3007,...}, {sku:3008,...} ] <-- list-backed variants
    ^ variant-level filter

    At the product level, we filter by the featured field inside each product map.

    At the variant level, we filter by the quantity field inside either:

    • a map-backed variant (keyed by SKU), or

    • a list-backed variant (array of objects).

    // Product-level filter: featured == true
    Exp filterOnFeatured = Exp.eq(
    MapExp.getByKey(
    MapReturnType.VALUE, Type.BOOL,
    Exp.val("featured"),
    Exp.mapLoopVar(LoopVarPart.VALUE) // the value of the element in this iteration is extracted into a loop variable whose data type is a map
    ),
    Exp.val(true)
    );
    // Variant-level filter: quantity > 0
    Exp filterOnVariantInventory = Exp.gt(
    MapExp.getByKey(
    MapReturnType.VALUE, Type.INT,
    Exp.val("quantity"),
    Exp.mapLoopVar(LoopVarPart.VALUE) // the value of the element in this iteration is extracted into a loop variable whose data type is a map
    ),
    Exp.val(0)
    );
  7. Run the path expression.

    Combine the filters with traversal contexts:

    // Operation
    Record record = client.operate(null, key,
    CdtOperation.selectByPath("inventory", Exp.SELECT_MATCHING_TREE,
    CTX.allChildren(), // dive into variants
    CTX.allChildrenWithFilter(filterOnFeatured), // only featured products
    CTX.mapKey(Value.get("variants")), // only 'variants' instances
    CTX.allChildrenWithFilter(filterOnVariantInventory)) // only in-stock
    );
  8. Observe the result.

    Print the returned dataset and notice that the server only returns products with featured = true and at least one variant in stock:

    System.out.println(record.getMap("inventory"));

    Expected output:

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

    ✅ Item 50000009 keeps both variants.

    ✅ Item 10000001, Classic T-Shirt, keeps variant items 2001 and 2003 (both have quantity > 0).

    ❌ Item 10000002, Casual Polo Shirt, excluded (featured = false).

    ❌ Variant 2002 excluded from item 10000001 (quantity = 0).

    ❌ Item 50000006 excluded, variant 3001 (quantity = 0).

Feature summary

With path expressions you can:

  • iterate over all the elements of a nested map or list collection data type, and use expressions at each iteration to filter out mismatches at each layer.

  • Retrieve only relevant subtrees (products + in-stock variants).

  • Avoid denormalization and client-side filtering.

  • Build faster, cleaner APIs for real-world use cases like product catalogs.

Next steps

Explore additional code examples and use cases on the Advanced usage page.

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?