
# Конструктор запитів

`DocStore` та `SegmentedLog` надають `query()`. `DocStore` може використовувати вторинні
індекси; `SegmentedLog` застосовує ті самі умови до потокових записів.

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

Корисні методи для завершення запиту:

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

У `DocStore` дві умови `eq` для неунікальних полів із індексацією за точною відповідністю
можуть використовувати автоматичний складений кошик. Окремі умови точної відповідності, `in` та оператори діапазону
й надалі використовують налаштовані індекси полів.

Оператори:

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

`andWhere` та `orWhere` використовують функції зворотного виклику, оскільки `and` та `or` зарезервовані PHP
ключові слова:

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

Послідовні виклики `where()` поєднуються оператором AND; кожна гілка `orWhere()` додає
альтернативу.

## Як виконується обробка

Кожна умова працює з будь-якою колекцією; індекси лише впливають на швидкість. У `DocStore` `eq` та `in` використовують індекси точної відповідності, оператори діапазону та `prefix` — індекси діапазонів, а `orderBy` з `limit` для поля з індексом діапазону читає дані в порядку індексу. В усіх інших випадках фільтрація виконується під час сканування записів. Якщо планувальник не може обслужити `orderBy` за індексом поля, відповідні записи сортуються в PHP, тож для великих колекцій додавайте до нього умови з індексами. Для `DocStore` `count()` використовує кількість записів в індексі, а для `SegmentedLog` — лічильники в пам’яті, якщо фільтр містить лише одну умову точної відповідності.

`cursor($id)` обмежує результати записами після цього ідентифікатора. Разом із `page()` це забезпечує стабільну пагінацію за ідентифікаторами записів. Про прості потокові фільтри без конструктора див. [Запити](https://storh.inline0.dev/uk/docs/queries).
