IndexedDB hello world
IndexedDB is one kind of storage provided by browsers,
alongside cookies, LocalStorage, and AppCache.
You may have heard that IndexedDB is a key-value store.
This may fool you into thinking that the IndexedDB API is similar to LocalStorage,
which does not have much more than getItem
and putItem
.
No! Compared to LocalStorage, IndexedDB has many additional concepts:
multiple DBs, multiple “object stores”, indexes, primary keys, DB upgrades, transactions.
Consequently, the “hello world” is pretty long.
This page has created a database called "testdb"
,
which has one table called "employees"
.
You can see this in Chrome by opening Developer Tools, going to Application, then IndexedDB.
The following form sets/gets values in the localStorage
for this website (jameshfisher.com
).
Like LocalStorage, IndexedDB storage is per-origin (for this site, https://jameshfisher.com:443
).
Unlike LocalStorage, each origin can create many key-value stores.
Each origin can have multiple databases.
The database "exampledb"
is “opened” with:
const req = indexedDB.open("exampledb", 1);
req.addEventListener("upgradeneeded", (ev) => {
const db = req.result;
// ...
});
req.addEventListener("success", () => {
const db = req.result;
// ...
});
There are two important listeners: success
and upgradeneeded
.
Databases in IndexedDB are versioned, and upgradeneeded
is used for database migrations.
A database version is a natural number, beginning at version 1.
If you view "exampledb"
in Developer Tools, you’ll see it’s at version 1.
A call to indexedDB.open("exampledb", n)
compares n
with the current version.
If current_version < n
, the upgradeneeded
listener is called.
Each database can have multiple object stores,
which are similar to tables in an RDBMS.
The "exampledb"
database has one object store called "employees"
.
Object stores can only be created in the upgradeneeded
listener
(similar to how tables in an RDBMS are conventionally only created in migrations).
Here’s the upgradeneeded
listener for "exampledb"
:
req.addEventListener("upgradeneeded", (ev) => {
const db = req.result;
db.createObjectStore("employees", { keyPath: "name" });
});
In the call to createObjectStore
,
the parameter keyPath
defines the primary key for objects in the store.
With keyPath
set to "name"
,
the object {name: "Jim", position: "CEO"}
will be stored under the key "Jim"
.
The other important listener is for success
,
which gives us our database handle:
req.addEventListener("success", () => {
const db = req.result;
// ...
});
With our db
handle in place, we can get/put items:
function putEmployee(employee) {
const tx = db.transaction(["employees"], "readwrite");
const employeeTable = tx.objectStore("employees");
employeeTable.put(employee);
}
function getEmployee(name, cb) {
valEl.value = localStorage.getItem(keyEl.value);
const tx = db.transaction(["employees"], "readonly");
const employeeTable = tx.objectStore("employees");
const getReq = employeeTable.get(name);
getReq.addEventListener("success", () => cb(getReq.result));
}
Tagged . All content copyright James Fisher 2017. This post is not associated with my employer.