Skip to content

Query recipes

Real-world patterns stitched from the primitives in find, aggregate, joins, bulk, and CAS. Send any of these as the payload to ./shard-db query '<json>' or over TCP.

1. Paginated filter with projection, sorted newest first

Return paid invoices from the last 30 days, newest first, 50 per page, only the fields a dashboard needs:

{"mode":"find","dir":"acme","object":"invoices",
 "criteria":[
   {"field":"status","op":"eq","value":"paid"},
   {"field":"paid_at","op":"gte","value":"20260318000000"}
 ],
 "fields":["id","customer","total","paid_at"],
 "order_by":"paid_at","order":"desc",
 "offset":0,
 "limit":50}

For the next page, bump offset by limit. find buffers all matches then sorts, so deep pagination over huge result sets pays O(matches). For raw full-scan pagination over an entire object (no filter), prefer fetch with keyset cursor. For sorted pagination on an indexed order_by field, use the find cursor — O(limit) per page, scales to deep offsets.

2. Group-by aggregate with HAVING (revenue by product)

Top 10 products by revenue, excluding any product that sold fewer than 100 units:

{"mode":"aggregate","dir":"acme","object":"orders",
 "criteria":[{"field":"status","op":"eq","value":"fulfilled"}],
 "group_by":["product_sku"],
 "aggregates":[
   {"fn":"count","alias":"units_sold"},
   {"fn":"sum","field":"line_total","alias":"revenue"},
   {"fn":"avg","field":"line_total","alias":"avg_ticket"}
 ],
 "having":[{"field":"units_sold","op":"gte","value":"100"}],
 "order_by":"revenue","order":"desc",
 "limit":10}

Output is tabular ({"columns":[...], "rows":[[...]]}) — drop-in for spreadsheets or charting libraries.

3. Multi-join: enrich orders with user email and product title

A left-join on products (emit nulls if the SKU is missing), inner-join on users (drop orders without a known user):

{"mode":"find","dir":"acme","object":"orders",
 "criteria":[{"field":"status","op":"eq","value":"paid"}],
 "join":[
   {"object":"users","local":"user_id","remote":"key",
    "as":"user","type":"inner","fields":["email","name"]},
   {"object":"products","local":"product_sku","remote":"sku",
    "as":"product","type":"left","fields":["title","price"]}
 ],
 "limit":100}

remote is either "key" (primary-key lookup) or any indexed field on the joined object. Output columns: orders.key, orders.{field}, user.{field}, product.{field}.

4. Safe bulk update with dry-run first

Mark all pending orders older than 7 days as expired. Dry-run first to see the blast radius, then run for real with a limit guard:

// Dry run — returns the would-be count without writing
{"mode":"bulk-update","dir":"acme","object":"orders",
 "criteria":[
   {"field":"status","op":"eq","value":"pending"},
   {"field":"created","op":"lt","value":"20260410000000"}
 ],
 "value":{"status":"expired"},
 "limit":10000,
 "dry_run":true}
// Execute (drop dry_run, same criteria)
{"mode":"bulk-update","dir":"acme","object":"orders",
 "criteria":[
   {"field":"status","op":"eq","value":"pending"},
   {"field":"created","op":"lt","value":"20260410000000"}
 ],
 "value":{"status":"expired"},
 "limit":10000}

Use CAS ("if":{"version":42}) on single-record updates for lock-free concurrency control. Combine with auto_update on a version:int field to track revisions.