Skip to content

Grouping sets of values


Often it may be necessary to organize your preferences or settings by grouping them according to context, their purpose, or a project.

The API has ability to group or categorize submitted values. It is definitely advisable to somehow group or categorize your data items (either by project, or a domain, etc.) - but the need will clearly depend on your use case. There is a way to logically organize the data into groups.

Groupings can be: 'project', 'domain', 'subdomain', and 'list'. To assign a piece of data to a group (like domain, subdomain, project name, or a list), add the parameter to your /write? query.

Those are all optional values but they may help tremendously with your data queries later. A full list of reserved grouping parameters is listed below.

Grouping query example


The .write() action below will save the user selected (presumably!) theme and store email addresses collected via a landing page for a project "my-app" and a domain (domain as in "knowledge domain") we called "front-page".

await db.project("my-app")
    .domain("front-page")
        .key("theme")
            .write("default-dark");
curl -s -b cookies.txt -H "X-Authorization: Token $KEY" -G https://prefsdb.com/api/v1/write/ \
  -d project=my-app -d domain=front-page -d theme=default-dark
await db.project("my-app")
    .domain("front-page")
        .list("waiting-list")
            .add("janedoe@someplace.com");
curl -s -b cookies.txt -H "X-Authorization: Token $KEY" -G https://prefsdb.com/api/v1/write/ \
  -d project=my-app -d domain=front-page -d list=waiting-list \
  --data-urlencode "*=janedoe@someplace.com"

The above query creates a list called "waiting-list" within the project named "my-app" and domain "front-page". As one could expect, a project can contain any number of domains, subdomains, or lists.

The theme settings can then be retrieved with a .read() query:

let theme = null;

const reply = await db.project("my-app")
    .domain("front-page")
        .key("theme")
            .read();

if (reply.success) {
    theme = reply.value;
}
curl -s -b cookies.txt -H "X-Authorization: Token $KEY" -G https://prefsdb.com/api/v1/read/ \
  -d project=my-app -d domain=front-page -d "theme="

Tip

Reads and deletes match the grouping exactly: a level you leave out matches only values stored without one. .expire(days) is the exception — there, a level you leave out matches any value (see Delete Ops).

Reserved keywords


The following keywords are used to identify a group of values. The keywords are all very abitrary - they are plain strings, and there is no meaning behind the names, and there is no naming convention. Their purpose is only to help with organization of the data. They can be combined together, so a domain can have several projects, or a single project several domains, it really is up to you, the developer, to decide how to organize the data for your own benefit.

Key name Description
project grouping variable
domain grouping variable
subdomain grouping variable
type [reserved]
list grouping variable; creates a list type collection

Don't use these as key names

Because they're request parameters, these words can't be used as the names of your own keys: project, domain, subdomain, type, list, name, ttl, key, hash, token, keyhash, __map, __filter, __history, __limit, __start, __after, __since and __ifVersion. Using one is refused with the error RESERVED_KEY_NAME: .key("name") throws it before anything is sent, and the API answers it to a direct request. Avoid other names starting with __ as well.

What are Lists?

Lists basically are collections of data grouped by a list name where duplicate keys are allowed. Submitted values with a duplicate key would typically be overridden. Unless (!) they are stored in a list. Lists are created by adding &list=[listname] parameter to your /write queries.

For instance, let's say we have a landing page for a product which collects emails of users interested in being notified about product updates. Normally, to save an email we'd simply send it to the write API:

await db.project("my-app")
    .key("email")
        .write("janedoe@someplace.com");
curl -s -b cookies.txt -H "X-Authorization: Token $KEY" -G https://prefsdb.com/api/v1/write/ \
  -d project=my-app --data-urlencode "email=janedoe@someplace.com"

Great! The problem is that if a field "email" already exists, this would update the email value with the new address - no duplicates rule. key/value pairs are by all means mutable. The seconds write operation (as shown below) will replace the existing value.

await db.project("my-app")
    .key("email")
        .write("june.bug@whereever.com");
curl -s -b cookies.txt -H "X-Authorization: Token $KEY" -G https://prefsdb.com/api/v1/write/ \
  -d project=my-app --data-urlencode "email=june.bug@whereever.com"

We don't want that. We want to collect multiple emails for our waitlist. To achieve that, we add them to a list called user-emails, with the .list() method:

await db.project("my-app").list("user-emails").add("janedoe@someplace.com");
await db.project("my-app").list("user-emails").add("june.bug@whereever.com");
curl -s -b cookies.txt -H "X-Authorization: Token $KEY" -G https://prefsdb.com/api/v1/write/ \
  -d project=my-app -d list=user-emails --data-urlencode "*=janedoe@someplace.com"
curl -s -b cookies.txt -H "X-Authorization: Token $KEY" -G https://prefsdb.com/api/v1/write/ \
  -d project=my-app -d list=user-emails --data-urlencode "*=june.bug@whereever.com"

Our list will now contain two email addresses.

The full list can be retrieved with a simple .read() query:

const result = await db.project("my-app")
    .list("user-emails")
        .read({ array: true });

// array: true -- result.values is an array however many entries there are
const myList = result.values;
curl -s -b cookies.txt -H "X-Authorization: Token $KEY" -G https://prefsdb.com/api/v1/read/ \
  -d project=my-app -d list=user-emails -d "*="

What are Maps?

A map is a named collection of key/value pairs. Unlike a list, writing an existing key in a map replaces its value.

await db.map("inventory").put("apples", 12);
await db.map("inventory").put("apples", 8);    // replaces 12

const apples = await db.map("inventory").get("apples");   // apples.value === 8
const all    = await db.map("inventory").readAll();       // all.values: every entry
const items  = await db.map("inventory").entries();       // [{ key: "apples", value: 8 }, ...]
curl -s -b cookies.txt -H "X-Authorization: Token $KEY" -G https://prefsdb.com/api/v1/write/ \
  -d __map=inventory -d apples=8
curl -s -b cookies.txt -H "X-Authorization: Token $KEY" -G https://prefsdb.com/api/v1/read/ \
  -d __map=inventory -d "apples="