Объект Table в Dexie.js представляет собой центральную
абстракцию для работы с отдельной таблицей в IndexedDB. Именно через
него выполняются операции чтения, записи, обновления и удаления данных,
а также формируются запросы с использованием цепочек вызовов. Каждая
таблица в базе данных Dexie.js соответствует экземпляру
Table, который инкапсулирует доступ к конкретному хранилищу
объектов и предоставляет богатый API для построения декларативных
запросов.
Экземпляр Table создаётся автоматически при объявлении
схемы базы данных через Dexie:
const db = new Dexie("AppDB");
db.version(1).stores({
users: "++id,name,age",
orders: "++id,userId,total"
});
const usersTable = db.table("users");
Каждая таблица связана с:
Основная особенность Table заключается в том, что он не
просто предоставляет CRUD-операции, а формирует ленивые запросы, которые
выполняются только при их материализации (например, через
toArray() или each()).
db.users.add({ name: "Alice", age: 25 });
Метод add() возвращает Promise, который
резолвится с ключом добавленной записи. Если используется
автоинкрементный ключ, он генерируется автоматически.
db.users.update(1, { age: 26 });
Обновление возможно как по первичному ключу, так и через модификацию
набора записей с использованием modify():
db.users.where("age").below(18).modify({ status: "minor" });
db.users.delete(1);
Или массовое удаление через запрос:
db.users.where("age").above(60).delete();
Одной из ключевых концепций Dexie.js является построение цепочек методов, которые формируют запрос к IndexedDB. Эти цепочки ленивые: до момента вызова терминального метода запрос не выполняется.
Цепочка обычно начинается с объекта Table и продолжается
через методы:
where()orderBy()filter()limit()offset()reverse()Завершается цепочка терминальными операциями:
toArray()first()last()each()count()Метод where() используется для создания индексированного
запроса:
db.users.where("age").above(18).toArray();
Здесь формируется диапазонное условие по индексу age.
Dexie оптимизирует такие запросы, используя возможности IndexedDB
индексов.
equals()above()below()between()anyOf()noneOf()Пример сложного диапазона:
db.users.where("age").between(18, 30, true, false);
Флаги включают или исключают границы диапазона.
Метод orderBy() задаёт сортировку по индексу:
db.users.orderBy("name").toArray();
Особенность заключается в том, что orderBy() требует
индексированного поля. В противном случае операция становится менее
эффективной.
Комбинация с reverse() позволяет инвертировать
порядок:
db.users.orderBy("age").reverse().toArray();
Метод filter() выполняет пост-обработку уже извлечённых
данных:
db.users.toCollection().filter(user => user.age > 18).toArray();
Важно понимать, что filter() работает на уровне
JavaScript после извлечения данных из IndexedDB, а не на уровне
индексов. Это влияет на производительность при больших объёмах
данных.
Метод limit() ограничивает количество возвращаемых
записей:
db.users.orderBy("age").limit(10).toArray();
Метод offset() пропускает указанное количество
элементов:
db.users.orderBy("age").offset(20).limit(10).toArray();
Такая комбинация используется для реализации пагинации.
После вызова where() или orderBy()
возвращается объект Collection, который расширяет
возможности Table. Именно Collection
поддерживает цепочки обработки данных.
Пример:
db.users
.where("age")
.above(18)
.filter(user => user.active)
.limit(5)
.toArray();
Каждый этап добавляет новый слой обработки, не выполняя запрос немедленно.
Материализует коллекцию в массив:
db.users.where("age").above(18).toArray();
Итерация по результатам без создания массива:
db.users.where("age").above(18).each(user => {
console.log(user.name);
});
Этот метод эффективен при обработке больших наборов данных.
Подсчёт количества записей:
db.users.where("age").above(18).count();
Получение первого или последнего элемента:
db.users.orderBy("age").first();
db.users.orderBy("age").last();
Цепочки Dexie.js не выполняют запросы немедленно. Вместо этого формируется описание запроса, которое исполняется только при вызове терминального метода. Это позволяет:
Пример:
const query = db.users.where("age").above(18);
query.limit(5); // ещё нет выполнения
query.toArray(); // выполнение запроса
Dexie.js позволяет комбинировать несколько уровней фильтрации:
db.users
.where("age")
.between(18, 60)
.and(user => user.active)
.toArray();
Метод and() добавляет дополнительное условие,
применяемое после первичного индексного отбора.
Методы map() и modify() позволяют
трансформировать данные:
db.users
.where("age")
.above(18)
.modify(user => {
user.status = "adult";
});
В отличие от filter(), modify() изменяет
данные в базе, а не только в памяти.
Цепочки можно сохранять в переменные и переиспользовать:
const adults = db.users.where("age").above(18);
adults.toArray();
adults.count();
Однако важно учитывать, что каждая терминальная операция выполняет отдельный запрос.
Эффективность цепочек зависит от:
where() и
orderBy();filter() на больших наборах;limit();IndexedDB работает наиболее эффективно при использовании индексированных полей, тогда как пост-фильтрация снижает производительность.
Каждый вызов метода добавляет шаг в цепочку обработки. Dexie строит внутренний план выполнения, который затем интерпретируется движком IndexedDB. Это позволяет разделять:
Такое разделение критично для оптимизации сложных запросов.
Цепочки могут комбинироваться для построения сложной логики выборки:
db.users
.where("age")
.above(18)
.and(user => user.country === "KZ")
.reverse()
.limit(20)
.toArray();
Каждый элемент цепочки уточняет результат предыдущего шага, формируя итоговый набор данных через последовательную фильтрацию и сортировку.