Dev Guide
Dev GuideUser GuideGitHubNuGetDevCommunityDoc feedbackLog In

Key value store

This topic describes how to store customer data using the key value store in Optimizely Connect Platform (OCP).

See SDK Reference for additional detail.

The Key-Value Store is a general-purpose key-value storage for convenient temporary or long-term storage of small to medium-sized data sets/objects. Similar to the secrets store, the key-value store provides atomic operations such as patch, but also includes increment, list, and set operations. The interface for the key-value store extends the same interface as the secrets and settings store, so the basic operations will be similar.

🚧

Important

Do not write sensitive data such as API keys, API tokens, usernames or passwords to the key-value store. While the data is encrypted at rest, it does not have the same level of security as the secret or setting stores and is not suitable for storing sensitive information.

Writing an object

As with the secret store, you can write a hash of primitive values such as string, number, boolean, arrays, and any other value that can be serialized with JSON.stringify. One major difference from the secret store is the KV Store will return the previous value if there was one.

import {storage} from '@zaius/app-sdk';
const order = {id: 123, status: 'pending'};
const previousValue = await storage.kvStore.put(`pending_order|${order.id}`, order);

Setting Time to Live (TTL)

You are strongly encouraged to set a TTL on all your short-term data stored in the key-value store to avoid never-ending growth. Setting a TTL allows your data to expire and automatically be purged from the key-value store. If you attempt to read or update an object that has expired, you get the same result as if the value never existed.

// Expire the order after 10 minutes
await storage.kvStore.put(`pending_order|${order.id}`, order, {ttl: 600});

Reading an object

interface PendingOrder {
  id: number;
  status: string;
}

const pendingOrder = await storage.kvStore.get<PendingOrder>(`pending_order|${orderId}`);
if (pendingOrder.status === 'pending') {
  // TODO
}

Updating an object

await storage.kvStore.patch(`pending_order|${orderId}`, {status: 'completed'});

// You can also enforce type safety
await storage.kvStore.patch<Partial<PendingOrder>>(key, update);

You can also perform more complicated updates with a callback:

interface Countdown {
  counter: number;
  step: number;
}
await storage.kvStore.patch('countdown', (value, options) => {
  // set the TTL to 60 seconds
  options.ttl = 60;
  // change the value
  value.counter -= value.step || 1;
  if (value.counter < 0) {
    value.counter = 0;
  }
  // return the value we want to set given the previous value
  return value;
});

📘

Note

You can call the update callback multiple times in order to ensure the operation completes atomically.

Checking if an object exists

if (await storage.kvStore.exists(`pending_order|${orderId}`)) {
  // we've already seen the order
}

Deleting an object

await storage.kvStore.delete(`pending_order|${orderId}`);

Features of the KV Store

Increment

You may find you need a consistent counter across all instances of your app, for example, to count the number of generated coupons you have remaining. To do this, you can rely on the increment method to atomically increment or decrement a value in the key-value store.

// Add one to the counter because we generated a new summer15 coupon
let remaining = await storage.kvStore.increment('coupons', 'summer15');

// subtract 5 from the counter because we just used 5 coupons
remaining = await storage.kvStore.increment('coupons', 'summer15', -5);

// add 10 to both our coupons
await storage.kvStore.incrementMulti('coupons', {summer15: 10, freeship: 10});

Lists (Arrays)

The KV Store supports special atomic operations on lists. See the SDK Reference for more detailed documentation. List operations include:

  • append, appendMulti
    • Atomically add one or more elements to the end of a list (or multiple lists)
  • peek, peekMulti
    • retrieve (without removing) one or more elements from the front of the list (or multiple lists)
  • shift, shiftMulti
    • Atomically remove (and retrieve) one or more elements from the front of the list (or multiple lists)unshift, unshiftMultiAtomically insert one or more elements at the front of a list (or multiple lists)

Sets

You can also use the KV Store to maintain a set of strings or numbers. In order to create a set of strings or numbers, you simply write a StringSet or NumberSet object to the key-value store. When you read the setback, it will be an instance of a StringSet or NumberSet.