Синтаксис описания схемы хранения в Dexie.js основан на декларативной строковой нотации, где структура таблицы задаётся через строку индексов, а также специальные символы для управления первичными ключами, уникальностью, композитными индексами и многозначными полями. Эта модель построена поверх IndexedDB, но существенно упрощает описание структуры данных, устраняя необходимость ручного создания object stores и индексов через низкоуровневые API.
Описание схемы выполняется внутри версии базы данных:
const db = new Dexie('AppDatabase');
db.version(1).stores({
users: 'id, name, age'
});
Каждое свойство объекта, переданного в stores,
соответствует отдельной таблице (object store). Значение — строка схемы,
определяющая:
Первичный ключ задаётся первым полем в строке схемы или явно через специальные префиксы.
users: '++id, name, age'
++id означает:
id — первичный ключusers: 'id, name, age'
В этом случае id становится первичным ключом, но без
автоинкремента.
Dexie также допускает использование строк или любых уникальных значений в качестве ключа, если автоинкремент не задан.
Индексы указываются перечислением полей после первичного ключа:
users: '++id, name, age, email'
Каждое поле создаёт индекс, позволяющий выполнять быстрые запросы:
db.users.where('age').above(18)
Индексы в Dexie соответствуют индексам IndexedDB, но создаются декларативно.
Для задания уникальности используется символ &:
users: '++id, &email, name'
&email означает:
Это эквивалентно уникальному constraint в SQL-системах.
Составные индексы задаются через квадратные скобки:
users: '++id, [name+age]'
Такой индекс позволяет эффективно выполнять запросы по комбинации полей:
db.users.where('[name+age]').equals(['Ivan', 30])
Особенности:
Многозначные индексы обозначаются символом *:
posts: '++id, title, *tags'
Если поле содержит массив:
{
id: 1,
title: 'Post',
tags: ['js', 'indexeddb', 'dexie']
}
то каждый элемент массива становится отдельной записью в индексе.
Это позволяет выполнять запросы вида:
db.posts.where('tags').equals('dexie')
В Dexie допускается комбинирование индикаторов в рамках одного поля:
posts: '++id, &slug, *tags, [type+created]'
Здесь:
++id — автоинкрементный первичный ключ&slug — уникальный индекс*tags — многозначный индекс[type+created] — составной индексПорядок полей в строке схемы критически важен:
Хотя Dexie допускает гибкость, логически первичный ключ всегда
извлекается из первого определённого поля или из ++.
Dexie поддерживает индексацию вложенных свойств через точечную нотацию:
users: '++id, address.city, address.country'
Это позволяет индексировать структуры:
{
id: 1,
address: {
city: 'Almaty',
country: 'Kazakhstan'
}
}
Запрос:
db.users.where('address.city').equals('Almaty')
Строковая схема Dexie имеет ряд ограничений:
Dexie работает на уровне индексации, а не строгой схемы данных.
Изменение структуры таблиц выполняется через версии:
db.version(1).stores({
users: '++id, name, age'
});
db.version(2).stores({
users: '++id, name, age, email'
});
При обновлении версии:
При изменении структуры данных часто требуется преобразование:
db.version(2).stores({
users: '++id, name, age, email'
}).upgrade(tx => {
return tx.table('users').toCollection().modify(user => {
user.email = user.email || '';
});
});
Миграции выполняются последовательно, в рамках транзакции версии базы.
Строка схемы разбирается Dexie парсером с учётом специальных символов:
++ — автоинкремент& — уникальность* — multiEntry[] — compound index. — вложенные поля, — разделитель индексовПример интерпретации:
'++id, &email, *tags, [a+b], profile.city'
Каждое объявление трансформируется в object store IndexedDB:
store.name → таблицаkeyPath → первичный ключindexes → IDBIndexDexie автоматически синхронизирует декларацию схемы с реальной структурой IndexedDB при инициализации версии.
Первичный ключ определяет:
put, add,
deleteПри использовании ++ Dexie делегирует генерацию ключей
движку IndexedDB, обеспечивая атомарность и уникальность.
Если новая версия схемы несовместима со старой:
Поэтому изменение схемы требует строгого контроля версий.
Схема в Dexie проектируется не как таблица SQL, а как набор индексов под конкретные запросы:
Такой подход формирует индексно-ориентированную модель хранения, где структура данных вторична по отношению к паттернам доступа