Read Data
Overview
Data can be retrieved using the equivalent function that were used to store it: key/value pairs, large data blobs or serialize and deserialize entire objects.
Syntax:
.read( [options] )
.readAll( [options] )
.pages( [options] )
.getItem( key, [options])
.getObject( fileId, [options])
.getObjectUrl( fileId, [options])
All functions return a Promise. You can also pass "onsuccess"/"onerror" handlers in the "Options" instead of awaiting it.
Parameters
| parameter | type | description |
|---|---|---|
| key | fileId | string | data key identifier, or the id of an uploaded file |
| options | { } | [Optional] An object containing additional parameters and overrides such as timeout, onsuccess, or onerror, and limit, after or start to read in pages (see Reading in pages). |
Promise vs. Callback
A Promise is always returned. The onsuccess/onerror callbacks, when given, are called as well.
.read()
The core read operation. Use either a Promise or a callback function to collect query results.
Usage:
Same grouping rules must be applied to read data, as when the data was written. For instance, if you saved an object under a specific project and domain, you must use the same parameters to retrieve that object.
let mySettings = { fontSize: 14, theme: "dark" };
/* save settings */
await db.project("foo").domain("bar")
.key("display-settings").write(mySettings);
/* restore settings */
const res = await db.project("foo").domain("bar")
.key("display-settings").read();
mySettings = res.value; // stored objects come back as objects
# save settings
curl -s -b cookies.txt -H "X-Authorization: Token $KEY" -G https://prefsdb.com/api/v1/write/ \
-d project=foo -d domain=bar --data-urlencode 'display-settings={"fontSize":14,"theme":"dark"}'
# restore settings
curl -s -b cookies.txt -H "X-Authorization: Token $KEY" -G https://prefsdb.com/api/v1/read/ \
-d project=foo -d domain=bar -d "display-settings="
.readAll()
Reads every value stored under your key, across all projects, domains and lists. After .map(name) or .list(name), it reads every entry of that map or list only.
Reading in pages
A list can grow to many thousands of values. Rather than fetching it all at once, read it a page at a time: pass limit, and each response tells you whether there's more and gives you next, the place to continue from. Values come back newest first.
# the newest 100 entries
curl -s -b cookies.txt -H "X-Authorization: Token $KEY" -G https://prefsdb.com/api/v1/read/ \
-d list=events -d "*=" -d __limit=100
# {"values":[...],"count":100,"more":true,"next":"MjAyNi0w..."}
# the 100 after those: pass "next" back as __after
curl -s -b cookies.txt -H "X-Authorization: Token $KEY" -G https://prefsdb.com/api/v1/read/ \
-d list=events -d "*=" -d __limit=100 --data-urlencode "__after=MjAyNi0w..."
To go through every page, .pages() follows next for you:
The paging options:
| option | HTTP parameter | description |
|---|---|---|
| limit | __limit |
How many values to return, from 1 up to 1,000. |
| after | __after |
Continue after the previous page: pass that response's next. |
| start | __start |
Skip this many values first, e.g. { limit: 100, start: 200 } for the third page. Use after or start, not both. |
A paged read always returns a values array, even when it holds one value or none ([]), so your loop doesn't need a special case for the last page. When more is false, there's nothing left to read.
A page can hold fewer values than limit asks for when the values are large: a single read returns at most 8 MB of data (more on paid plans). It always holds at least one value, however large, and more and next tell you to keep going. So decide whether to read again from more, not from how many values came back.
after or start?
With start, values added while you're paging push the older ones down, so the next page can repeat a value (or, after a delete, skip one). after always continues exactly where the last page ended. Use after for anything that's being written to, like a log or a feed.
A single read returns at most 1,000 values. If you read without limit and more than that match, you get the newest 1,000 with more: true and a next to continue from, plus a warning. Asking for a limit above the maximum returns an error (LIMIT_TOO_LARGE) instead of a shorter page.
Paged reads always go to the server; they're never answered from the offline cache.
.getItem()
Convenience method for familiarity with local Storage in a browser. However, unlike localStorage methods, this call is asynchronous. Use a Promise or a callback function to retrieve the query result.
Usage:
.getObject()
Download a file uploaded with .putObject(), by the file id from the upload's response. Use the same project/domain/subdomain/list as the upload.
Usage:
.getObjectUrl()
Get a web address for a file uploaded with .putObject(), so you can use it right in your page, for example as an image's src, without downloading the file first. Use the same project/domain/subdomain/list as the upload.
The address shows images, audio, video, PDFs and plain text in the page. Other files, and HTML or SVG always, are downloaded instead. Anyone who has the address can open the file, so share it only where you want that.
The response of .putObject() already contains the same addresses (shareViewUrl to show, shareUrl to download); use this method when you only have the file id.
Usage:
Options: { download: true } resolves to the address that downloads the file; { details: true } resolves to the whole response (file, name, size, shareUrl, shareViewUrl).
# Needs a getkey call from the last 60 seconds (see Getting started).
curl -s -b cookies.txt -H "X-Authorization: Token $KEY" \
-G https://prefsdb.com/api/v1/getobject/ -d file=$FILE_ID -d domain=uploads -d url=1
# -> {"success":true,"shareViewUrl":"https://prefsdb.com/dl/?t=...&view=1","shareUrl":"https://prefsdb.com/dl/?t=...", ...}
Response
Generally a response will contain a combination of the fields below. Which ones? it mostly depends on the status of the query. For example, a successful response will not have error message.
{
status : "string",
success : boolean,
ts : "string|number",
count : number,
value : any,
values : [ ],
more : boolean,
next : "string",
modifiedt : "string",
version : number,
changeSeq : number,
error : "string",
message : "string"
}
The response will contain one of the value or values fields, depending on how many values matched (count). When exactly one value matches, value holds it. When several match, values is an array of them. This applies to lists, .readAll() and scope reads too: a list with a single entry comes back as value.
more is true when there are further values to read, and next is then where to continue from (see Reading in pages). A read that asks for a page (limit, after or start) always uses values.
Generally, reading one key returns a single value, and operations like .readAll() will typically return an array of data objects, thus the values field. Each entry in values holds the key name and its value, e.g. { "theme": "dark", "uid": "12345", "modifiedt": "2026-08-13 12:00:00", "version": 41 }.
version (on a key or map entry, not a list entry) changes every time the value is written, and changeSeq marks the moment of the read: use them to change a value only if nobody else did, and to ask what changed since.
Always an array: array and .entries()
So your code doesn't have to handle both shapes, pass { array: true }: the response then always has values, with no entries, one or many. Or call .entries(), which gives you the rows as a plain array of { key, value } objects (plus uid, modifiedt and, where the read spans several, the row's scope):
.entries() rejects with the error if the read fails. One read returns at most 1,000 rows on the free plan, and the array tells you when it stopped short: items.more is true when more rows matched (the browser console says so too), and items.next continues from there ({ after: items.next }). To get every row, pass max, and .entries() reads page after page for you:
const all = await db.map("todos").entries({ max: Infinity }); // every row
const some = await db.map("todos").entries({ max: 5000 }); // at most 5,000
For very large collections, read in pages so you can show the first rows sooner.
Callbacks vs Promises
All methods return a Promise. If you'd rather use callbacks, pass them in the options ({ onsuccess: ..., onerror: ... }); they're called with the same response.
Examples
Read key/value
First, include the PrefsDB JavaScript library in your project:
This defines the PrefsDB class; PrefsDB.getkey() gives you the db instance used below (see Getting started).
Note
The HTTP API returns values as stored (text). The JavaScript client turns values that were stored as JSON back into objects, numbers and booleans.
Deserialize an object
To retrieve the saved instance of an object (deserialization) we read it back by its key.
Lists
Lists are un-ordered collections of data. Prefsdb.com makes it easy and effortless to collect data in a list.