diff --git a/README.md b/README.md index 2ef9cf2..a4f2343 100644 --- a/README.md +++ b/README.md @@ -127,15 +127,16 @@ We’ll filter at two levels of the data: When traversing with Path Expressions, the server evaluates filters at different depths. Here’s the stack we’re walking for this example: ``` -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 +catalog (bin) + └── inventory (map entry) + └── 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 product level, we filter by the `featured` field inside each product map. @@ -337,9 +338,11 @@ Exp filterOnKey = // Operation Record record = client.operate(null, key, - CdtOperation.selectByPath(binName, Exp.SELECT_MAP_KEY, + CdtOperation.selectByPath(binName, Exp.SELECT_MAP_KEY | Exp.SELECT_NO_FAIL, CTX.allChildren(), - CTX.allChildrenWithFilter(filterOnKey) + CTX.allChildrenWithFilter(filterOnKey), + CTX.mapKey(Value.get("variants")), + CTX.allChildrenWithFilter(filterOnVariantInventory) ) ); @@ -359,11 +362,11 @@ Expected Output: Filters can be chained with `AND` / `OR`. -**Example**: Select variants that are in stock and have price < 50 (across all products). +**Example**: Select variants that are in stock, have price < 50 (across all products), and are featured. **Note**: Unlike the previous examples focused on featured products for homepage promotion, this example demonstrates filtering at the variant level only, without a product-level filter. This pattern is useful for different scenarios like finding clearance items, budget options, or inventory that meets specific criteria across your entire catalog. -When you run the demo, look for the output labeled **"ADVANCED EXAMPLE 3: Combining multiple filters (price < 50 AND quantity > 0)"** in your terminal. +When you run the demo, look for the output labeled **"ADVANCED EXAMPLE 3: Combining multiple filters (price < 50 AND quantity > 0 AND featured = true)"** in your terminal. ```java Exp filterOnCheapInStock = Exp.and( @@ -381,7 +384,7 @@ Exp filterOnCheapInStock = Exp.and( Record record = client.operate(null, key, CdtOperation.selectByPath(binName, Exp.SELECT_MATCHING_TREE, CTX.allChildren(), // Navigate into all products - CTX.allChildren(), // Navigate deeper into product structure + CTX.allChildrenWithFilter(filterOnFeatured), // Navigate deeper into the featured product structure CTX.mapKey(Value.get("variants")), // Navigate to variants map/list CTX.allChildrenWithFilter(filterOnCheapInStock) // Filter variants by price and quantity ) @@ -485,7 +488,7 @@ Record noFailResponse = client.operate(null, key, With `NO_FAIL`, `malformed_product` excluded silently because variants was "no variant". -When you run the demo, look for the output labeled **"ADVANCED EXAMPLE 5: NO_FAIL flag to tolerate malformed data"** in your terminal. You'll first see **"❌ Operation failed as expected (malformed data without NO_FAIL flag)"** showing the operation fails without NO_FAIL, then **"✅ Operation succeeded with NO_FAIL flag:"** showing the successful operation with the flag. +When you run the demo, look for the output labeled **"ADVANCED EXAMPLE 6: NO_FAIL flag to tolerate malformed data"** in your terminal. You'll first see **"❌ Operation failed as expected (malformed data without NO_FAIL flag)"** showing the operation fails without NO_FAIL, then **"✅ Operation succeeded with NO_FAIL flag:"** showing the successful operation with the flag. Expected output: @@ -569,4 +572,4 @@ Exposes metadata of the current element (key, value, or index) during traversal. **Returns**: -An `Exp` object usable inside filter or modifying expressions. \ No newline at end of file +An `Exp` object usable inside filter or modifying expressions. diff --git a/src/main/java/com/aerospike/pathexpressions/PathExpressionsDemo.java b/src/main/java/com/aerospike/pathexpressions/PathExpressionsDemo.java index 7ad71c8..d717864 100644 --- a/src/main/java/com/aerospike/pathexpressions/PathExpressionsDemo.java +++ b/src/main/java/com/aerospike/pathexpressions/PathExpressionsDemo.java @@ -54,7 +54,7 @@ public static void main(String[] args) throws IOException { AerospikeClient client = new AerospikeClient(clientPolicy, new Host("localhost", 3000)); // Truncate the inventory set client.truncate(null, "test", "products", null); - String binName = "inventory"; + String binName = "catalog"; // insert the inventory Key key = new Key("test", "products", "catalog"); client.put(null, key, new Bin(binName, inventory)); @@ -122,9 +122,11 @@ public static void main(String[] args) throws IOException { System.out.println("ADVANCED EXAMPLE 2: Alternate return modes with Exp.SELECT_"); System.out.println("=".repeat(80)); Record regexList = client.operate(null, key, - CdtOperation.selectByPath(binName, Exp.SELECT_MAP_KEY, + CdtOperation.selectByPath(binName, Exp.SELECT_MAP_KEY | Exp.SELECT_NO_FAIL, CTX.allChildren(), - CTX.allChildrenWithFilter(filterOnKey))); + CTX.allChildrenWithFilter(filterOnFeatured), + CTX.mapKey(Value.get("variants")), + CTX.allChildrenWithFilter(filterOnVariantInventory))); System.out.println("Result (MAP_KEYS only): " + Debug.print(regexList.getList(binName))); @@ -147,7 +149,7 @@ public static void main(String[] args) throws IOException { Record cheapInStock = client.operate(null, key, CdtOperation.selectByPath(binName, Exp.SELECT_MATCHING_TREE, CTX.allChildren(), - CTX.allChildren(), + CTX.allChildrenWithFilter(filterOnFeatured), CTX.mapKey(Value.get("variants")), CTX.allChildrenWithFilter(filterOnCheapInStock))); @@ -276,6 +278,11 @@ public static void main(String[] args) throws IOException { System.out.println("✅ Operation succeeded with NO_FAIL flag:"); System.out.println(Debug.print(noFailResponse.getValue(binName))); + // Remove malformed data and return record to initial state + WritePolicy policy = new WritePolicy(); + policy.recordExistsAction = RecordExistsAction.REPLACE; + client.put(policy, key, new Bin(binName, inventory)); + client.close(); } }