Метод update() в Dexie.js используется для частичного
обновления существующих записей в хранилище IndexedDB без необходимости
перезаписывать весь объект целиком. Он работает на уровне одной записи и
опирается на ключевой идентификатор объекта или индекс, по которому
выполняется поиск.
table.update(key, changes)
key — первичный ключ записи или значение
индексированного поля, по которому происходит поиск.changes — объект с полями, которые необходимо
изменить.Метод возвращает промис, который резолвится в:
1, если запись была успешно найдена и обновлена;0, если запись с указанным ключом не найдена.update() выполняет частичное обновление объекта в
хранилище. Это означает, что изменяются только указанные поля, остальные
данные записи сохраняются без изменений.
В отличие от put(), который полностью заменяет объект,
update() изменяет только перечисленные свойства, что делает
его более эффективным при небольших правках.
const db = new Dexie("MyDatabase");
db.version(1).stores({
users: "id, name, age"
});
await db.users.add({ id: 1, name: "Alice", age: 25 });
await db.users.update(1, { age: 26 });
В данном случае изменяется только поле age, остальные
данные записи остаются нетронутыми.
Если запись с указанным ключом не существует, метод не вызывает
ошибку, а возвращает 0.
const result = await db.users.update(999, { age: 30 });
// result === 0
Это поведение позволяет безопасно использовать update()
без предварительной проверки существования записи.
update() не требует передачи полного объекта. Можно
обновить только одно поле:
await db.users.update(1, { name: "Bob" });
Если объект содержит вложенные структуры, обновление происходит только на верхнем уровне.
await db.users.update(1, {
profile: { city: "Almaty" }
});
В этом случае поле profile будет полностью заменено
новым объектом.
Метод работает только с верхнеуровневыми свойствами. Глубокое слияние объектов не выполняется автоматически. Это означает, что:
Пример поведения с массивами:
await db.users.update(1, {
tags: ["admin", "editor"]
});
Старое значение массива полностью заменяется новым.
Обновление возможно не только по первичному ключу, но и через индекс, если он уникален.
db.version(1).stores({
users: "id, email, name"
});
await db.users.update("alice@mail.com", {
name: "Alice Updated"
});
Здесь обновление происходит по полю email, если оно
объявлено как индекс.
Возвращаемое значение позволяет определить, была ли запись изменена:
const updated = await db.users.update(1, { age: 40 });
if (updated) {
console.log("Обновление выполнено");
} else {
console.log("Запись не найдена");
}
Это часто используется в логике условного обновления без
предварительного get().
В Dexie.js существует альтернативный метод modify(),
который часто используется совместно с where() и
курсорами.
Основные различия:
update() — работает с одной записью по ключу или
уникальному индексу;modify() — может обновлять множество записей через
запрос.await db.users.where("age").below(30).modify({ status: "young" });
update() в этом смысле более точечный и прямолинейный
инструмент.
В случаях, когда требуется сложная логика обновления, часто используется комбинация:
const user = await db.users.get(1);
if (user && user.age < 30) {
await db.users.update(1, { status: "young" });
}
Хотя update() сам по себе не поддерживает условия, он
хорошо сочетается с предварительной выборкой данных.
Если переданные поля не соответствуют схеме объекта, Dexie.js не выполняет строгую валидацию, так как IndexedDB является схемо-независимым хранилищем. Однако это может привести к:
Пример:
await db.users.update(1, { age: "twenty five" });
Значение будет сохранено как строка без преобразования.
update() не поддерживает функцию в качестве значения
поля. Следующий код не будет работать:
// некорректно
await db.users.update(1, {
age: age => age + 1
});
Для подобных операций используется modify() или
предварительное получение значения:
const user = await db.users.get(1);
await db.users.update(1, {
age: user.age + 1
});
Если переданные изменения не отличаются от текущих значений, IndexedDB всё равно может выполнить операцию записи, хотя фактическое состояние данных не изменится. Dexie.js не выполняет глубокого сравнения объектов перед обновлением.
Метод update() может использоваться внутри транзакций
для обеспечения атомарности операций:
await db.transaction("rw", db.users, async () => {
await db.users.update(1, { status: "active" });
await db.users.update(2, { status: "inactive" });
});
В случае ошибки в транзакции все изменения будут отменены.
При массовых операциях update() может использоваться в
цикле, однако это менее эффективно, чем bulkPut() или
modify():
for (const item of updates) {
await db.users.update(item.id, { age: item.age });
}
Такой подход приводит к последовательным операциям записи, что может снижать производительность при больших объёмах данных.
На уровне IndexedDB операция update() фактически
реализуется как:
Dexie.js упрощает этот процесс, скрывая работу с курсорами и транзакциями, но логика остаётся аналогичной.
Типичные сценарии, приводящие к ошибкам:
Пример:
await db.transaction("r", db.users, async () => {
await db.users.update(1, { name: "Test" });
});
В режиме только чтения операция завершится с ошибкой.
update() чаще всего применяется в ситуациях, где
требуется:
Типичный сценарий:
await db.orders.update(orderId, {
status: "shipped",
shippedAt: Date.now()
});
Такой подход уменьшает количество операций чтения и снижает нагрузку на IndexedDB.