Методы keys() и primaryKeys() в Dexie.js
используются для получения ключей записей из таблицы или запроса, но
работают на разных уровнях индексации и дают принципиально различный
результат по смыслу и производительности.
Оба метода возвращают массив или поток значений ключей, однако важно понимать, какие именно ключи извлекаются: либо ключи индекса/курсорного обхода, либо первичные ключи объектов. Это различие критично при работе с большими наборами данных и составными индексами.
Метод keys() возвращает значения индекса, по которому
выполняется обход запроса. Это означает, что результат зависит от того,
как именно сформирован запрос: используется ли where(),
orderBy(), или полный перебор таблицы.
При вызове на таблице без индексового ограничения keys()
возвращает первичные ключи записей, но при использовании индекса —
значения именно этого индекса.
const db = new Dexie("MyDB");
db.version(1).stores({
users: "++id, name, age"
});
// получение ключей (по первичному ключу)
const ids = await db.users.toCollection().keys();
При работе через индекс:
const names = await db.users.where("age").above(18).keys();
В этом случае возвращаются значения индекса age, а не
id.
whereCollection и TabletoArray(), так как не извлекает
полные объектыМетод primaryKeys() всегда возвращает именно первичные
ключи таблицы, независимо от того, какой индекс используется в
запросе.
Это делает его предсказуемым инструментом при любых фильтрациях и сортировках.
const db = new Dexie("MyDB");
db.version(1).stores({
users: "++id, name, age"
});
// первичные ключи всех записей
const ids = await db.users.toCollection().primaryKeys();
Даже если запрос выполняется по индексу:
const ids = await db.users.where("age").above(18).primaryKeys();
результатом всё равно будут значения id, а не
age.
bulkDelete,
bulkGetwhere,
orderBy, filterРассмотрим таблицу:
db.version(1).stores({
users: "++id, name, age"
});
Данные:
| id | name | age |
|---|---|---|
| 1 | Alex | 20 |
| 2 | Bob | 30 |
| 3 | Carol | 30 |
Запрос:
```javascript
const res1 = await db.users.where("age").equals(30).keys();
const res2 = await db.users.where("age").equals(30).primaryKeys();
Результат:
keys() → [30, 30]primaryKeys() → [2, 3]Это демонстрирует фундаментальную разницу: keys()
работает на уровне индекса age, а
primaryKeys() — на уровне сущностей таблицы.
Оба метода используют курсоры IndexedDB, но различаются тем, какие данные извлекаются из транзакции.
keys() читает только ключ курсора (index key)primaryKeys() делает дополнительное разрешение к
primary key при обходе индексаНесмотря на это, primaryKeys() всё равно значительно
быстрее, чем toArray(), так как не сериализует весь
объект.
При больших выборках разница становится особенно заметной:
// медленнее — полные объекты
await db.users.where("age").above(18).toArray();
// быстрее — только первичные ключи
await db.users.where("age").above(18).primaryKeys();
Оба метода принадлежат API Collection, поэтому применимы
после where(), filter(), limit(),
offset().
db.users
.where("age")
.above(18)
.limit(10)
.keys();
db.users
.where("age")
.above(18)
.limit(10)
.primaryKeys();
Важно учитывать, что filter() выполняется на уровне
JavaScript после извлечения курсора, поэтому ключи уже получены и просто
преобразуются.
При использовании orderBy() поведение также
различается:
db.users.orderBy("age").keys();
db.users.orderBy("age").primaryKeys();
keys() → значения age в отсортированном
порядкеprimaryKeys() → id записей в порядке
сортировки по ageЭто особенно важно при построении пагинации, где требуется сохранять стабильный порядок первичных идентификаторов.
При работе с compound index:
db.version(1).stores({
orders: "++id, [userId+createdAt]"
});
db.orders.orderBy("[userId+createdAt]").keys();
Результатом будут кортежи индекса:
[userId, createdAt]А:
db.orders.orderBy("[userId+createdAt]").primaryKeys();
вернёт только id записей.
Метод primaryKeys() часто применяется как
подготовительный шаг для bulk-операций:
const ids = await db.users.where("age").above(18).primaryKeys();
await db.users.bulkDelete(ids);
Такой подход позволяет избежать загрузки полных объектов, минимизируя память и время обработки.
| Метод | Что возвращает | Нагрузка |
|---|---|---|
toArray() |
Полные объекты | высокая |
keys() |
ключи индекса | низкая |
primaryKeys() |
первичные ключи | низкая–средняя |
При необходимости передачи данных между слоями приложения выбор между
keys() и primaryKeys() становится
архитектурным решением: либо работать с индексами, либо с сущностями
таблицы.
Оба метода возвращают пустой массив при отсутствии совпадений, без исключений:
const keys = await db.users.where("age").above(200).keys();
// []
const ids = await db.users.where("age").above(200).primaryKeys();
// []
Если индекс не уникален, keys() может возвращать
повторяющиеся значения:
db.users.where("age").keys(); // [30, 30, 30]
primaryKeys() всегда возвращает уникальные
идентификаторы записей, поскольку опирается на первичный ключ:
// [2, 3, 5]
keys() — отражает структуру индекса запросаprimaryKeys() — стабильно отражает идентичность
записейwhere, orderBy, составных индексов и
bulk-операций