Метод toArray() и toCollection()

Метод toArray() в Dexie.js служит для преобразования результата запроса IndexedDB в обычный массив JavaScript. Он является завершающей операцией (terminal operation), которая материализует ленивый результат запроса и выполняет фактическое чтение данных из базы.

В Dexie.js toArray() доступен не только у коллекций, но и у таблиц и некоторых запросов через where().

Поведение метода

При вызове toArray():

  • выполняется запрос к IndexedDB;
  • все подходящие записи считываются полностью;
  • результат собирается в массив;
  • возвращается Promise, который резолвится этим массивом.

Особенность заключается в том, что до вызова toArray() большинство операций в Dexie остаются ленивыми, особенно при использовании цепочек фильтрации и сортировки.

Сигнатура

collection.toArray(): Promise<Array<T>>

Пример использования с таблицей

const users = await db.users.toArray();

В этом случае:

  • считываются все записи из таблицы users;
  • результатом становится массив объектов пользователей.

Пример с фильтрацией через where()

const adults = await db.users
  .where("age")
  .aboveOrEqual(18)
  .toArray();

Здесь происходит:

  • построение индексированного запроса по полю age;
  • выборка всех пользователей старше или равных 18 лет;
  • возврат массива результатов.

Пример с Collection

const result = await db.users
  .orderBy("age")
  .filter(user => user.active)
  .toArray();

В этом случае:

  • сначала формируется отсортированная коллекция;
  • затем применяется JavaScript-фильтр;
  • затем выполняется материализация в массив.

Производительность и особенности

toArray() следует рассматривать как операцию, которая:

  • загружает все данные в память;
  • может быть дорогой при больших выборках;
  • блокирует дальнейшую ленивость запроса.

Ключевые моменты:

  • IndexedDB отдаёт данные потоково, но Dexie собирает их целиком;
  • при больших таблицах может возникать нагрузка на память;
  • использование limit() до toArray() уменьшает объём выборки.
const latest = await db.logs
  .orderBy("timestamp")
  .reverse()
  .limit(100)
  .toArray();

Метод toCollection()

Метод toCollection() преобразует результат запроса Table или WhereClause в объект Collection, позволяя продолжить построение цепочки операций над набором данных.

В отличие от toArray(), он не завершает выполнение запроса, а наоборот — переводит его в расширяемую форму.

Назначение

toCollection() используется для:

  • унификации результата в виде Collection;
  • применения дополнительных операций фильтрации, сортировки и агрегации;
  • преобразования различных типов запросов в единый интерфейс обработки.

Сигнатура

table.toCollection(): Collection<T, IndexType>

Пример использования с таблицей

const collection = db.users.toCollection();

Результат:

  • создаётся коллекция, содержащая все записи таблицы;
  • дальнейшие операции выполняются лениво.

Пример с where()

const collection = db.users
  .where("age")
  .above(18)
  .toCollection();

Здесь:

  • сначала создаётся индексированный запрос;
  • затем он превращается в Collection;
  • появляется возможность использовать методы Collection API.

Пример дальнейшей обработки

const result = await db.users
  .where("age")
  .above(18)
  .toCollection()
  .filter(user => user.active)
  .sortBy("name");

Логика выполнения:

  • IndexedDB отбирает пользователей по индексу;
  • Dexie преобразует результат в Collection;
  • применяется JavaScript-фильтр;
  • выполняется сортировка на стороне клиента;
  • результат материализуется в массив (через sortBy()).

Различие между toArray() и toCollection()

Семантика

  • toArray() — завершает запрос и возвращает данные;
  • toCollection() — преобразует запрос в промежуточную форму для дальнейших операций.

Поведение в цепочке

db.users.where("age").above(18).toArray();
  • запрос завершается;
  • возвращается массив.
db.users.where("age").above(18).toCollection();
  • запрос не завершается;
  • возвращается Collection;
  • можно продолжать цепочку.

Когда используется toArray()

  • когда нужен готовый результат;
  • при выводе данных в UI;
  • при сериализации;
  • при простых запросах без дальнейшей обработки.

Когда используется toCollection()

  • при сложной фильтрации;
  • при комбинировании нескольких операций;
  • при построении повторно используемых цепочек;
  • при необходимости применять методы Collection API.

Внутренние особенности выполнения

Dexie.js строит выполнение запросов по принципу:

  1. IndexedDB выполняет только индексные операции (where, orderBy);
  2. Dexie формирует Collection;
  3. JavaScript-операции (filter, map) выполняются в памяти;
  4. toArray() запускает финальную материализацию.

Влияние цепочек

db.users
  .where("age")
  .above(18)
  .filter(u => u.active)
  .toArray();

Порядок:

  • IndexedDB: age > 18;
  • Dexie: фильтрация active;
  • сбор в массив.

Чем позже вызывается toArray(), тем больше операций попадает в JS-слой.


Использование с сортировкой и ограничениями

Сортировка через Collection

const list = await db.users
  .toCollection()
  .sortBy("createdAt");

Ограничение выборки

const last10 = await db.users
  .orderBy("createdAt")
  .reverse()
  .limit(10)
  .toArray();

Разница:

  • limit() влияет на объем данных до материализации;
  • toArray() фиксирует результат.

Типичные сценарии применения

Загрузка данных для интерфейса

const items = await db.products
  .where("category")
  .equals("books")
  .toArray();

Постобработка на клиенте

const activeUsers = await db.users
  .toCollection()
  .filter(u => u.active)
  .sortBy("name");

Комбинированные выборки

const result = await db.orders
  .where("status")
  .anyOf(["new", "processing"])
  .toCollection()
  .filter(o => o.total > 100)
  .toArray();

Особенности работы с памятью и асинхронностью

Оба метода работают поверх IndexedDB, который является асинхронным хранилищем. Это означает:

  • каждый вызов возвращает Promise;
  • выполнение происходит неблокирующим образом;
  • данные не доступны синхронно.

Потенциальные проблемы

  • использование toArray() на больших наборах приводит к росту потребления памяти;
  • toCollection() при неправильной фильтрации может переносить слишком много операций в JavaScript;
  • отсутствие limit() в цепочке увеличивает нагрузку.

Поведение при изменении данных во время запроса

Запросы IndexedDB в Dexie работают в рамках транзакционной модели:

  • данные фиксируются на момент выполнения запроса;
  • изменения после начала чтения не попадают в результат;
  • toArray() возвращает консистентный снимок данных.

Комбинирование с другими методами Collection

После toCollection() доступны методы:

  • filter()
  • map()
  • each()
  • sortBy()
  • count()

Пример цепочки:

const names = await db.users
  .toCollection()
  .filter(u => u.age > 18)
  .map(u => u.name)
  .sortBy(name => name);

Разграничение ответственности методов

  • toArray() фиксирует результат и завершает вычисление;
  • toCollection() сохраняет ленивую модель и расширяет возможности обработки.

Разница между ними формирует основу управления запросами Dexie.js: либо ранняя материализация, либо построение цепочки трансформаций перед финальным извлечением данных.