Key-Value Store closed beta

kv.png

Introduction

OWN3D's Key-Value Store is a very simple NoSQL databases that allows you to store and retrieve data. It is designed to be used for small amounts of data, such as settings, preferences, and other small pieces of data.

It also features client-side encryption, which means that the data is encrypted before it is sent to the server. The server only sees the encrypted data and cannot decrypt it. The encryption key is stored on the client-side and is never sent to the server.

Values can be up to 16 KB in size. The free tier has a limit of 10,000 operations per month and a maximum storage of 10 MB. Verified Developers can request a higher limit.

WARNING

The Key-Value Store is for backend use only. It is not designed to be used in the frontend. For frontend use, we recommend using the Remote Config Service or combining the Key-Value Store with your own backend.

Installation

We recommend using at least version 0.2.0-rc.2 or higher of the key-value store client. You can find the latest version on the JSRopen in new window website. Versions below 0.2.0 are not compatible with environment variables and client-side encryption.

To install the key-value store client, run the following command:

# deno
deno add jsr:@gz/kv

# npm (use any of npx, yarn dlx, pnpm dlx, or bunx)
npx jsr add @gz/kv

Opening the Key-Value Store

Every Key-Value Store has a unique Access Token and is used to access the Key-Value Store. You should keep it secret and never expose it in your frontend code.

import { connect } from "@gz/kv";

const kv = await connect({
    bucket: '9d1cb4c7-c683-4fa9-bc5f-13f5ad1ba745',
    accessToken: '9b9634a1-1655-4baf-bdf5-c04feffc68bd',
    region: 'eu-central-1'
});

TIP

You can use environment variables to configure the key-value store. The key-value store client will automatically use the environment variablesopen in new window if they are set.

const kv = await connect();

Creating a User interface

Since we're going to use TypeScript, we can create an interface for our User object. So it's easier to work with. Here we define a User interface with a name and an email for example.

interface User {
    name: string;
    email: string;
}

Creating, updating, and reading a key-value pair

Now, we can create our first key-value pair. We use the set() method to create a new key-value pair. The key is an array of strings and the value is the value you want to store. Internally, the key-array is joined with a separator to create a unique key.

const key = ['users', '1'];
const value: User = {name: 'GhostZero', email: 'example@example.com'};
await kv.set(key, value);

Once the key-value pair is created, you can read it back using the get() method. The get() method returns an object with the key, value, and version.

const key = ['users', '1'];
const entry = await kv.get<User>(key);

console.log(entry.key);
console.log(entry.value);
console.log(entry.version);

Deleting a key-value pair

You can delete a key-value pair using the delete() method. The delete() method returns a boolean indicating if the key-value pair was deleted.

const key = ['users', '1'];
await kv.delete(key);

Atomic transactions

The OWN3D Key-Value Store supports atomic transactions. This means that you can perform multiple operations in a single transaction. If any of the operations fail, the entire transaction is rolled back.

const key = ['users', '1'];
const value: User = {name: 'GhostZero', email: 'example@example.com'};

const res = await kv.atomic()
    .check({key, version: null /* or a version */})
    .set(key, value)
    .commit();

if (res.ok) {
    console.log('Entry did not exist and was created');
} else {
    console.log('Entry already exist. No changes were made');
}

Improve querying with secondary indexes

With the Key-Value Store, you can only query by the key. If you want to query by a different field, you can create a secondary index. A secondary index is a key-value pair where the key is the field you want to query by and the value is the primary key.

async function saveUser(user: User) {
    const key = ['users', user.id];

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

    // set the secondary key's value to be the primary key
    await kv.set(['users_by_email', user.email], key);

    return r;
}

async function getById(id) {
    // use as usual
    return await kv.get<User>(['users', id]);
}

async function getByEmail(email) {
    // lookup the primary key by the secondary key
    const r1 = await kv.get<array[]>(['users_by_email', email]);
    const r2 = await kv.get<User>(r1.value);
    return r2;
}