Storh

Query Builder

DocStore and SegmentedLog expose query(). DocStore can use secondary indexes; SegmentedLog applies the same predicates over streamed records.

$records = $docs
    ->query()
    ->where('kind')->eq('page')
    ->where('status')->in(['draft', 'published'])
    ->where('publishedAt')->between($from, $until)
    ->orderBy('publishedAt', 'desc')
    ->limit(50)
    ->get();

Useful terminal methods:

$docs->query()->where('slug')->eq('home')->first();
$docs->query()->where('kind')->eq('page')->count();
$docs->query()->cursor($lastId)->page(100)->get();
$docs->query()->where('slug')->eq('home')->explain();

On DocStore, two eq conditions on non-unique equality-indexed fields can use an automatic compound bucket. Single equality, in, and range operators continue to use their configured field indexes.

Operators:

  • eq, neq
  • in, notIn
  • gt, gte, lt, lte, between
  • exists, missing
  • prefix
  • andWhere, orWhere
  • orderBy, limit, cursor, page

andWhere and orWhere use callbacks because and and or are reserved PHP keywords:

$docs->query()
    ->where('kind')->eq('page')
    ->orWhere(fn ($q) => $q->where('kind')->eq('post')->where('featured')->eq(true))
    ->get();

Chained where() calls combine with AND; each orWhere() branch adds an alternative.

What executes how

Every condition works on every collection; indexes only change the cost. On DocStore, eq and in resolve through equality indexes, the range operators and prefix resolve through range indexes, and orderBy with limit on a range-indexed field reads in index order. Everything else filters a record scan. orderBy on a field the planner cannot serve from an index sorts the matched records in PHP, so on large collections pair it with indexed conditions. count() uses index entry counts on DocStore and in-memory counters on SegmentedLog when the filter is a single equality.

cursor($id) restricts results to records after the id, which combines with page() for stable pagination ordered by record id. For plain streaming filters without the builder, see Queries.

On this page