Получение по ключу: get()

Метод get() в Dexie.js используется для получения одной записи из хранилища по первичному ключу или по индексированному значению. Он является одним из базовых способов чтения данных и работает поверх IndexedDB, скрывая сложность транзакций и запросов низкого уровня.

При работе с get() важно учитывать, что операция всегда возвращает только один объект либо undefined, если запись не найдена. Это отличает его от методов, возвращающих коллекции, таких как toArray() или where(). get() ориентирован на прямой доступ к конкретной сущности, что делает его максимально быстрым способом выборки данных при наличии ключа.

В простейшем виде метод вызывается через таблицу:

db.table.get(key)

где key — это значение первичного ключа записи.

Пример:

const user = await db.users.get(1);

В этом случае будет выполнен запрос к таблице users, и возвращён объект пользователя с первичным ключом 1.

Если запись отсутствует, результатом будет undefined:

const user = await db.users.get(999);
// user === undefined

Асинхронная природа выполнения

Метод get() всегда возвращает Promise. Это связано с тем, что IndexedDB является асинхронным API.

db.users.get(1).then(user => {
    console.log(user);
});

или с использованием async/await:

async function loadUser() {
    const user = await db.users.get(1);
    return user;
}

Асинхронность делает метод совместимым с современными потоками выполнения JavaScript и позволяет избегать блокировки основного потока.

Использование с индексами

get() может работать не только с первичным ключом, но и с уникальными индексами. Если индекс объявлен как unique, Dexie позволяет использовать его для прямого получения записи:

const user = await db.users.get({ email: "test@example.com" });

В этом случае поиск выполняется по индексу email. Важно, что индекс должен быть уникальным, иначе поведение может быть неоднозначным или метод вернёт первую подходящую запись.

Поведение при сложных ключах

Если таблица использует составной ключ (compound key), get() принимает массив значений:

const item = await db.orders.get([userId, orderId]);

Такой подход применяется, когда первичный ключ состоит из нескольких частей, например [userId+orderId]. Dexie корректно формирует запрос к IndexedDB и выполняет точное совпадение.

Отличие от where()

Метод get() не выполняет фильтрацию по набору условий. Он всегда возвращает максимум одну запись. В отличие от него:

  • where() возвращает коллекцию
  • filter() выполняет постобработку
  • get() выполняет прямой точечный доступ

Пример сравнения:

// точечный доступ
const user = await db.users.get(1);

// выборка по условию
const users = await db.users.where("age").above(18).toArray();

get() предпочтителен там, где известен ключ или уникальный индекс, поскольку работает быстрее и не требует перебора.

Обработка отсутствующих данных

Одной из ключевых особенностей является необходимость обработки undefined:

const user = await db.users.get(1);

if (!user) {
    console.log("Запись не найдена");
}

Отсутствие проверки может привести к ошибкам при попытке доступа к свойствам объекта.

Использование с транзакциями

get() может выполняться внутри транзакций, что обеспечивает согласованность данных:

await db.transaction("r", db.users, async () => {
    const user = await db.users.get(1);
});

В этом случае чтение происходит в рамках изолированного контекста, что важно при одновременных изменениях данных.

Оптимизация и производительность

get() является одной из самых быстрых операций чтения, так как:

  • использует индекс напрямую
  • не требует сканирования таблицы
  • выполняет минимальное количество операций в IndexedDB

Однако производительность зависит от правильного проектирования схемы. Если запрос выполняется не по индексу, Dexie может быть вынужден выполнить дополнительную обработку, что снижает эффективность.

Особенности работы с кэшированием

Dexie может использовать внутренние оптимизации, но get() не гарантирует кэширование результатов. Каждый вызов рассматривается как отдельный запрос к IndexedDB. Поэтому при частых обращениях к одним и тем же данным иногда целесообразно хранить результат в памяти приложения.

Поведение при изменении данных

Если запись изменяется между вызовами get(), каждый новый вызов вернёт актуальное состояние на момент выполнения запроса:

const user1 = await db.users.get(1);

await db.users.update(1, { name: "New Name" });

const user2 = await db.users.get(1);

user2 будет содержать обновлённые данные.

Использование с динамическими ключами

get() часто применяется в сценариях, где ключ формируется динамически:

function loadUser(id) {
    return db.users.get(Number(id));
}

Важно следить за типами ключей, так как IndexedDB чувствителен к строгому соответствию значений. Строка “1” и число 1 могут рассматриваться как разные ключи.

Ограничения метода

Несмотря на простоту, метод имеет ряд ограничений:

  • невозможность возврата нескольких записей
  • отсутствие встроенной фильтрации
  • необходимость точного совпадения ключа
  • зависимость от структуры индексов

Эти ограничения являются следствием того, что get() работает как низкоуровневая операция прямого доступа, а не как инструмент выборки данных.

Использование в архитектуре приложений

get() часто применяется в слоях доступа к данным, где требуется быстрый retrieval объектов по идентификатору:

  • загрузка профиля пользователя
  • получение настроек
  • доступ к кэширующим сущностям
  • восстановление состояния интерфейса

В таких сценариях он выступает базовой операцией чтения, вокруг которой строится остальная логика работы с IndexedDB.