Работа с ограничением выборки в Dexie.js основана на механизмах курсорной навигации IndexedDB и позволяет управлять количеством возвращаемых записей, а также смещением начала выборки. Эти операции особенно важны при реализации пагинации, постраничного вывода данных и оптимизации запросов к локальной базе.
Dexie.js предоставляет два ключевых метода для этих целей:
limit() и offset(). Они применяются к объекту
запроса (Collection) и могут комбинироваться с фильтрацией,
сортировкой и индексированными выборками.
Любая операция ограничения выборки в Dexie.js начинается с формирования коллекции:
db.users
.orderBy('age')
.toArray();
После получения коллекции можно применять методы ограничения:
limit(n) — ограничивает количество возвращаемых
записейoffset(n) — пропускает первые n
записейМетод limit() задаёт верхнюю границу количества
элементов, которые будут возвращены из коллекции. Он работает на уровне
курсора и останавливает итерацию после достижения указанного числа
записей.
collection.limit(n)
где n — максимальное количество записей.
db.users
.orderBy('age')
.limit(10)
.toArray()
.then(users => {
console.log(users);
});
В данном случае будет возвращено не более 10 пользователей, отсортированных по возрасту.
limit() не изменяет исходные данные, а влияет только на
выборку.
Ключевые особенности:
orderBy)where() и
filter()db.users
.where('role')
.equals('admin')
.limit(5)
.toArray()
В этом случае сначала происходит поиск по индексу role,
затем ограничение результата до 5 записей.
Метод offset() задаёт количество первых записей, которые
необходимо пропустить перед началом возврата результата.
collection.offset(n)
где n — количество пропускаемых элементов.
db.users
.orderBy('age')
.offset(10)
.toArray()
Результат будет содержать всех пользователей, начиная с 11-й записи в отсортированном списке.
В отличие от SQL-систем, где OFFSET может быть
относительно дешёвым при индексах, в IndexedDB реализация Dexie.js
использует курсорную прокрутку. Это означает:
Наиболее типичный сценарий — пагинация:
const pageSize = 20;
const pageNumber = 3;
db.users
.orderBy('age')
.offset(pageNumber * pageSize)
.limit(pageSize)
.toArray()
Логика:
pageNumber * pageSize записейpageSizeПорядок вызова методов имеет значение, так как Dexie.js строит цепочку обработки курсора:
collection.offset(10).limit(5)
и
collection.limit(5).offset(10)
могут давать одинаковый результат в простых случаях, но логически правильной и предсказуемой является последовательность:
orderBy(...).offset(...).limit(...)
offset() имеет фундаментальные ограничения, связанные с
природой IndexedDB:
Поэтому при больших наборах данных использование offset становится узким местом.
В Dexie.js предпочтительнее использовать курсорную пагинацию через
where() и ключи.
db.users
.where('age')
.above(lastSeenAge)
.limit(20)
.toArray()
Такой подход позволяет:
При работе внутри транзакции:
db.transaction('r', db.users, async () => {
const result = await db.users
.orderBy('age')
.offset(5)
.limit(10)
.toArray();
return result;
});
поведение остаётся идентичным, но важно учитывать:
Без orderBy() поведение может стать
недетерминированным:
db.users
.limit(10)
.toArray()
В этом случае порядок зависит от внутреннего порядка хранения IndexedDB, который не гарантируется.
Сортировка фиксирует последовательность:
db.users
.orderBy('id')
.offset(10)
.limit(10)
При составных индексах:
db.orders
.orderBy('[userId+date]')
.offset(20)
.limit(10)
.toArray()
Dexie.js применяет ограничения уже после построения упорядоченного курсора по композитному ключу.
Если результат фильтрации пустой:
db.users
.where('age')
.above(1000)
.offset(10)
.limit(10)
.toArray()
то:
offset() не выполняет обходlimit() не имеет эффектаlimit(0) всегда возвращает пустой результатoffset(0) эквивалентен отсутствию смещенияoffset + limit формирует окно выборкиwhere()/filter(), затем ограничениеЧасто встречаются следующие ошибки:
1. Использование offset без orderBy
db.users.offset(10).limit(5)
Результат нестабилен и не гарантирует воспроизводимости.
2. Попытка использовать offset как прямой доступ по индексу
IndexedDB не поддерживает произвольный доступ по позиции.
3. Большие offset в UI-пагинации
При больших таблицах это приводит к деградации производительности.
Эти методы не являются самостоятельными механизмами извлечения данных. Они выступают как слой управления курсором, который накладывается поверх:
where()orderBy()filter()Их основная функция — ограничение объёма данных, проходящих через цепочку обработки, а не оптимизация доступа к произвольным участкам данных.