
# Abfrage-Builder

`DocStore` und `SegmentedLog` stellen `query()` bereit. `DocStore` kann Sekundärindizes verwenden; `SegmentedLog` wendet dieselben Bedingungen auf gestreamte Datensätze an.

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

Nützliche Methoden zum Abschluss:

```php
$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();
```

Bei `DocStore` können zwei `eq`-Bedingungen für nicht eindeutige, gleichheitsindizierte Felder einen automatischen gemeinsamen Bucket verwenden. Einzelne Gleichheitsbedingungen, `in` und Bereichsoperatoren verwenden weiterhin ihre konfigurierten Feldindizes.

Operatoren:

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

`andWhere` und `orWhere` verwenden Rückruffunktionen, da `and` und `or` reservierte PHP-Schlüsselwörter sind:

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

Verkettete Aufrufe von `where()` werden mit UND kombiniert; jeder `orWhere()`-Zweig fügt eine Alternative hinzu.

## So werden Abfragen ausgeführt

Jede Bedingung funktioniert mit jeder Sammlung; Indizes beeinflussen nur den Aufwand. Bei `DocStore` werden `eq` und `in` über Gleichheitsindizes aufgelöst, Bereichsoperatoren und `prefix` über Bereichsindizes. `orderBy` mit `limit` für ein bereichsindiziertes Feld liest die Datensätze in Indexreihenfolge. Alles andere filtert einen Datensatz-Scan. `orderBy` für ein Feld, das der Planer nicht über einen Index bedienen kann, sortiert die passenden Datensätze im Arbeitsspeicher von PHP. Kombiniere es bei großen Sammlungen daher mit indizierten Bedingungen. `count()` verwendet bei `DocStore` die Anzahl der Indexeinträge und bei `SegmentedLog` Zähler im Arbeitsspeicher, sofern der Filter aus einer einzelnen Gleichheitsbedingung besteht.

`cursor($id)` beschränkt die Ergebnisse auf Datensätze nach der angegebenen ID. In Verbindung mit `page()` ermöglicht das eine stabile Paginierung nach Datensatz-ID. Einfache Streaming-Filter ohne Builder werden unter [Abfragen](https://storh.inline0.dev/de/docs/queries) beschrieben.
