Spec-Zone.ru › Deno 2

Быстрый старт Deno KV

Deno KV — это база данных ключ-значение, встроенная непосредственно в среду Deno, доступная в Deno.Kv пространстве имён. Она может использоваться для многих задач хранения данных, но особенно хорошо подходит для хранения простых структур данных, которые выигрывают от очень быстрых операций чтения и записи. Deno KV доступен в командной строке Deno и в Deno Deploy.

Давайте разберём ключевые особенности Deno KV.

Открытие базы данных

В вашей программе Deno вы можете получить ссылку на базу данных KV, используя Deno.openKv(). Вы можете передать необязательный путь к файловой системе, где вы хотите хранить свою базу данных, в противном случае она будет создана в текущем рабочем каталоге вашего скрипта.

const kv = await Deno.openKv();

Создание, обновление и чтение пары ключ-значение

Данные в Deno KV хранятся в виде пар ключ-значение, подобно свойствам объекта JavaScript или Map. Ключи представлены в виде массива типов JavaScript, таких как string, number, bigint, или boolean. Значения могут быть произвольными объектами JavaScript. В этом примере мы создаём пару ключ-значение, представляющую пользовательские настройки интерфейса, и сохраняем её с помощью kv.set().

const kv = await Deno.openKv();

const prefs = {
  username: "ada",
  theme: "dark",
  language: "en-US",
};

const result = await kv.set(["preferences", "ada"], prefs);

После того, как пара ключ-значение установлена, вы можете прочитать её из базы данных с помощью kv.get():

const entry = await kv.get(["preferences", "ada"]);
console.log(entry.key);
console.log(entry.value);
console.log(entry.versionstamp);

Оба get и list операции возвращают объект KvEntry со следующими свойствами:

  • key — массив ключей, используемый для установки значения
  • value — объект JavaScript, установленный для данного ключа
  • versionstamp — сгенерированное значение, используемое для определения, был ли ключ обновлён.

Операция set также используется для обновления объектов, уже существующих для данного ключа. При обновлении значения ключа его versionstamp изменится на новое сгенерированное значение.

Вывод нескольких пар ключ-значение

Чтобы получить значения для конечного числа ключей, вы можете использовать kv.getMany(). Передайте несколько ключей в качестве аргументов, и вы получите массив значений для каждого ключа. Обратите внимание, что значения и отметки времени могут быть null, если для данного ключа(ей) нет значения.

const kv = await Deno.openKv();
const result = await kv.getMany([
  ["preferences", "ada"],
  ["preferences", "grace"],
]);
result[0].key; // ["preferences", "ada"]
result[0].value; // { ... }
result[0].versionstamp; // "00000000000000010000"
result[1].key; // ["preferences", "grace"]
result[1].value; // null
result[1].versionstamp; // null

Часто бывает полезно получить список пар ключ-значение для всех ключей, которые разделяют заданный префикс. Такая операция возможна с помощью kv.list(). В этом примере мы получаем список пар ключ-значение, которые разделяют префикс "preferences".

const kv = await Deno.openKv();
const entries = kv.list({ prefix: ["preferences"] });
for await (const entry of entries) {
  console.log(entry.key); // ["preferences", "ada"]
  console.log(entry.value); // { ... }
  console.log(entry.versionstamp); // "00000000000000010000"
}

Возвращаемые ключи упорядочены лексикографически в зависимости от следующей компоненты ключа после префикса. Таким образом, пары KV с ключами:

  • ["preferences", "ada"]
  • ["preferences", "bob"]
  • ["preferences", "cassie"]

будут возвращены в этом порядке операцией kv.list().

Операции чтения могут выполняться в режиме сильной или условной согласованности. Режим сильной согласованности гарантирует, что операция чтения вернёт последнее записанное значение. Режим условной согласованности может вернуть устаревшее значение, но работает быстрее. Напротив, записи всегда выполняются в режиме сильной согласованности.

Удаление пар ключ-значение

Вы можете удалить ключ из базы данных, используя kv.delete(). Никаких действий не выполняется, если для данного ключа нет значения.

const kv = await Deno.openKv();
await kv.delete(["preferences", "alan"]);

Атомарные транзакции

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

const kv = await Deno.openKv();

const key = ["preferences", "alan"];
const value = {
  username: "alan",
  theme: "light",
  language: "en-GB",
};

const res = await kv.atomic()
  .check({ key, versionstamp: null }) // `null` versionstamps mean 'no value'
  .set(key, value)
  .commit();
if (res.ok) {
  console.log("Preferences did not yet exist. Inserted!");
} else {
  console.error("Preferences already exist.");
}

Узнайте больше о транзакциях в Deno KV здесь.

Улучшение запросов с помощью вторичных индексов

Вторичные индексы хранят одни и те же данные по нескольким ключам, позволяя упростить запросы к необходимым данным. Допустим, нам нужно получить доступ к пользовательским настройкам по имени пользователя ИЛИ по электронной почте. Чтобы включить это, вы могли бы предоставить функцию, которая оборачивает логику сохранения настроек, чтобы создать два индекса.

const kv = await Deno.openKv();

async function savePreferences(prefs) {
  const key = ["preferences", prefs.username];

  // Set the primary key
  const r = await kv.set(key, prefs);

  // Set the secondary key's value to be the primary key
  await kv.set(["preferencesByEmail", prefs.email], key);

  return r;
}

async function getByUsername(username) {
  // Use as before...
  const r = await kv.get(["preferences", username]);
  return r;
}

async function getByEmail(email) {
  // Look up the key by email, then second lookup for actual data
  const r1 = await kv.get(["preferencesByEmail", email]);
  const r2 = await kv.get(r1.value);
  return r2;
}

Узнайте больше о вторичных индексах в руководстве здесь.

Отслеживание обновлений в Deno KV

Вы также можете прослушивать обновления из Deno KV с помощью kv.watch(), которые будут передавать новые значения или значения ключа или ключей, которые вы предоставите. В примере чата ниже мы отслеживаем обновления ключа ["last_message_id", roomId]. Мы получаем messageId, которое затем используем с kv.list() для получения всех новых сообщений из seen и messageId.

let seen = "";
for await (const [messageId] of kv.watch([["last_message_id", roomId]])) {
  const newMessages = await Array.fromAsync(kv.list({
    start: ["messages", roomId, seen, ""],
    end: ["messages", roomId, messageId, ""],
  }));
  await websocket.write(JSON.stringify(newMessages));
  seen = messageId;
}

Узнайте больше о использовании отслеживания Deno KV здесь.

Использование в производстве

Deno KV доступен для использования в живых приложениях на Deno Deploy. В производстве Deno KV поддерживается FoundationDB, открытым хранилищем ключ-значение, созданным Apple.

Дополнительная настройка не требуется для запуска ваших программ Deno, использующих KV на Deploy — новая база данных Deploy будет предоставлена вам при необходимости вашим кодом. Узнайте больше о Deno KV в Deno Deploy здесь.

Тестирование

По умолчанию, Deno.openKv() создаёт или открывает постоянное хранилище на основе пути, из которого запускался скрипт, вызвавший его. Это обычно нежелательно для тестов, которым необходимо производить одинаковое поведение при многократном запуске.

Чтобы протестировать код, использующий Deno KV, вы можете использовать специальный аргумент ":memory:" для создания временного хранилища Deno KV.

async function setDisplayName(
  kv: Deno.Kv,
  username: string,
  displayname: string,
) {
  await kv.set(["preferences", username, "displayname"], displayname);
}

async function getDisplayName(
  kv: Deno.Kv,
  username: string,
): Promise<string | null> {
  return (await kv.get(["preferences", username, "displayname"]))
    .value as string;
}

Deno.test("Preferences", async (t) => {
  const kv = await Deno.openKv(":memory:");

  await t.step("can set displayname", async () => {
    const displayName = await getDisplayName(kv, "example");
    assertEquals(displayName, null);

    await setDisplayName(kv, "example", "Exemplary User");

    const displayName = await getDisplayName(kv, "example");
    assertEquals(displayName, "Exemplary User");
  });
});

Это работает, потому что Deno KV поддерживается SQLite при выполнении для локального развития. Как и в случае с базами данных SQLite в оперативной памяти, несколько временных хранилищ Deno KV могут существовать одновременно без взаимных помех. Дополнительную информацию о специальных режимах адресации баз данных см. в документации SQLite по этому вопросу.

Дальнейшие шаги

На данном этапе вы только начинаете знакомиться с Deno KV. Обязательно ознакомьтесь с нашим руководством по пространству имён Deno KV и набором уроков и примеров приложений здесь.

© 2018–2024 the Deno authors
Licensed under the MIT License.
https://docs.deno.com/deploy/kv/manual

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API