count()Метод count() в Dexie.js используется для получения
количества записей, удовлетворяющих определённому запросу, без
необходимости загружать сами данные в память. Он возвращает
Promise<number>, что делает его полностью асинхронным
и интегрированным с моделью работы IndexedDB.
Основная цель:
count() на
уровне таблицы (Table.count())Самый простой и наиболее производительный вариант подсчёта — вызов метода напрямую у таблицы.
const db = new Dexie("AppDB");
db.version(1).stores({
users: "++id, name, age, role"
});
const totalUsers = await db.users.count();
console.log(totalUsers);
В этом случае Dexie использует нативный механизм IndexedDB
count() по индексу или по primary key, что обеспечивает
минимальные накладные расходы.
Особенности:
where() и индексыПри использовании индексированных запросов count()
остаётся эффективным, так как IndexedDB может ограничить диапазон
напрямую по индексу.
const adminsCount = await db.users
.where("role")
.equals("admin")
.count();
Или диапазон:
const adultsCount = await db.users
.where("age")
.aboveOrEqual(18)
.count();
В этих случаях:
role или ageПри работе с compound-index Dexie использует лексикографический порядок ключей IndexedDB.
db.version(1).stores({
orders: "++id, [status+priority], status, priority"
});
const count = await db.orders
.where("[status+priority]")
.between(["open", 1], ["open", 5])
.count();
Особенности:
count() и
filter(): полная потеря оптимизацииИспользование filter() переводит выполнение в режим
перебора всех записей.
const count = await db.users
.filter(user => user.age % 2 === 0)
.count();
Поведение:
Фактически это эквивалент:
На больших объёмах данных это становится дорогостоящей операцией.
count() от
toArray().lengthЧастая ошибка — использовать загрузку массива для подсчёта:
const count = (await db.users.toArray()).length;
Сравнение:
| Метод | Поведение | Производительность |
|---|---|---|
count() |
подсчёт на уровне IndexedDB | высокая |
toArray().length |
загрузка всех данных | низкая |
count() всегда предпочтителен при отсутствии
необходимости работать с данными.
count() может быть частью цепочек Dexie Query API.
const activeAdmins = await db.users
.where("role").equals("admin")
.and(user => user.active === true)
.count();
Здесь важно:
where) использует индексand() уже выполняется в JScount() зависит от количества отфильтрованных
результатовСледствие:
and() оптимизация частично теряетсяcount() в
Collection и QueryDexie разделяет поведение:
Table.count() — прямой доступ к таблицеCollection.count() — после where()Query.count() — после orderBy() или
цепочекПример с сортировкой:
const count = await db.users
.orderBy("age")
.above(30)
.count();
Даже при orderBy() используется индекс, но:
Метод count() может деградировать в следующих
случаях:
filter() или
and()Полный перебор всех записей.
Если поле не индексировано:
db.users.where("nonIndexedField").equals("x").count();
Dexie вынужден сканировать всю таблицу.
Даже индексированный count может быть дорогим при миллионах записей, если диапазон широкий.
count() выполняется внутри текущей транзакции и
подчиняется её ограничениям.
db.transaction("r", db.users, async () => {
const count = await db.users.count();
console.log(count);
});
Особенности:
Все варианты count() возвращают Promise:
const count = await db.users.count();
или
db.users.count().then(c => {
console.log(c);
});
Характеристики:
Поведение count() напрямую зависит от схемы базы:
filter() всегда O(n)Пример оптимальной схемы:
db.version(1).stores({
logs: "++id, type, createdAt, status"
});
Подсчёты:
await db.logs.where("status").equals("error").count();
await db.logs.where("createdAt").above(Date.now() - 86400000).count();
Dexie использует snapshot-поведение IndexedDB транзакций:
Пример для пагинации:
const total = await db.products.where("category").equals("books").count();
const pages = Math.ceil(total / pageSize);
count() и ручной агрегациейDexie не предоставляет серверных агрегатов кроме
count(), поэтому:
count() — единственная нативная агрегирующая
операцияfilter() или
and()