Метод put() в Dexie.js реализует операцию вставки с
возможным обновлением (upsert) в таблицах IndexedDB. Его ключевая
особенность заключается в том, что он не требует предварительной
проверки существования записи: если объект с указанным первичным ключом
уже присутствует в хранилище, запись будет перезаписана, иначе —
добавлена как новая.
Внутренне put() опирается на механизм IndexedDB
put операции объекта хранилища, что обеспечивает
атомарность и предсказуемое поведение при работе с ключами.
При вызове put() происходит следующее:
Promise.Простейшая форма использования:
await db.users.put({
id: 1,
name: "Alex",
age: 30
});
Если в таблице users уже есть запись с
id = 1, она будет полностью заменена новым объектом.
put() возвращает Promise, который
резолвится в значение первичного ключа вставленной или обновлённой
записи.
const key = await db.users.put({
id: 5,
name: "Maria"
});
Если первичный ключ задан явно (id: 5), возвращаемым
значением будет 5. Если используется автоинкремент, будет
возвращён сгенерированный ключ.
put() от
add()Разница между put() и add() принципиальна и
влияет на поведение при конфликте ключей.
add()put()await db.users.add({ id: 1, name: "A" }); // ошибка, если id=1 уже существует
await db.users.put({ id: 1, name: "A" }); // безопасное обновление
Dexie.js определяет первичный ключ таблицы через схему
stores():
db.version(1).stores({
users: "id, name, age"
});
В этом случае id является ключевым полем. При
использовании put():
id присутствует в объекте — он используется как
ключ;При использовании ++id Dexie позволяет автоматически
генерировать ключи:
db.version(1).stores({
users: "++id, name, age"
});
Тогда:
await db.users.put({
name: "John",
age: 25
});
поведёт себя следующим образом:
id, он будет сгенерирован
автоматически;put() с тем же id запись
будет перезаписана.Важно понимать, что put() заменяет запись целиком, а не
частично.
await db.users.put({
id: 10,
name: "Anna"
});
Если ранее объект выглядел так:
{
id: 10,
name: "Anna",
age: 40,
city: "Almaty"
}
после put():
{
id: 10,
name: "Anna"
}
Все отсутствующие поля удаляются, поскольку IndexedDB хранит объект как единое значение.
put() не предназначен для частичного обновления. Для
таких сценариев используется:
update()modify() (Dexie Collection API)Попытка использовать put() как патч-операцию приводит к
потере данных.
bulkPut()Dexie.js предоставляет оптимизированный вариант массовой вставки/обновления:
await db.users.bulkPut([
{ id: 1, name: "A" },
{ id: 2, name: "B" },
{ id: 3, name: "C" }
]);
Особенности:
put();put() часто применяется внутри транзакций Dexie:
await db.transaction("rw", db.users, async () => {
await db.users.put({ id: 1, name: "Updated" });
await db.users.put({ id: 2, name: "Another" });
});
Характеристики:
Конфликт в put() трактуется не как ошибка, а как замена
записи. Однако ошибки могут возникать в случаях:
Пример конфликта уникального индекса:
db.version(1).stores({
users: "id, email"
});
Если email объявлен как уникальный индекс, попытка
вставить дубликат вызовет исключение даже при использовании
put().
put() возвращает Promise и всегда выполняется
асинхронно:
db.users.put({ id: 1, name: "Test" })
.then(key => {
console.log("Saved key:", key);
})
.catch(err => {
console.error("Error:", err);
});
Dexie оборачивает IndexedDB API в промисы, обеспечивая удобную цепочку обработки.
Хотя put() возвращает только ключ, часто требуется
получить обновлённый объект:
await db.users.put({ id: 1, name: "Updated" });
const user = await db.users.get(1);
Это важно, поскольку put() не возвращает сохранённый
объект целиком.
put() учитывает все индексы таблицы. При сохранении:
where().await db.users.bulkPut(serverUsers);
Используется для зеркалирования состояния backend.
await db.cache.put({
key: "profile_1",
data: profileData,
updatedAt: Date.now()
});
await db.settings.put({
id: "theme",
value: "dark"
});
await db.users.put({ id: 1, name: "OnlyName" });
Если объект содержал другие поля, они будут удалены.
Если таблица не определяет корректный первичный ключ:
db.version(1).stores({
users: "name" // нет уникального id
});
put() может вести себя неожиданно при дубликатах
значений name.
put() вместо частичного обновленияawait db.users.put({
id: 1,
age: 31
});
Приведёт к потере всех остальных полей записи.
put() оптимизирован для массовых операций, но его
производительность зависит от:
bulkPut() вместо циклов.bulkPut() почти всегда предпочтительнее при пакетной
записи.
Dexie добавляет поверх IndexedDB:
IDBObjectStore.put.Это делает put() более предсказуемым по сравнению с
нативным IndexedDB API, где требуется ручное управление транзакциями и
событиями onsuccess/onerror.
При повторных вызовах put() с теми же данными:
Dexie поддерживает hooks (creating,
updating, deleting), которые могут быть
вызваны при put():
creating — при вставке новой записи;updating — при обновлении существующей.Это позволяет внедрять логику валидации и трансформации данных до записи в IndexedDB.