The modern way of setting up IndexedDB

thorwurtzner

Thor Würtzner

Posted on August 18, 2021

The modern way of setting up IndexedDB

Updated for Aug 2021


Look! What is that? Is it a plane? is it localStorage?
No, it's IndexedDB - an unnecessarily complicated low-level API for client-side storage of lots of structured data.
I would like to meet the person who instantly understands how to implement it into their project, because he might have the ability to crack this modern version of the Enigma Code.

Pathetic jokes aside; I was required to use this pretty cool way of storing data for a school project, and decided to document how I made it work. For my future self, and any other frustrated developer who has also started yelling at their rubber ducky for not giving the answer.

To make it very clear, I know very little of what goes on behind the API, but simply how I personally made it work - and how you, future Thor, might also need to.
SO! Let's get started.

IndexedDB isn't exactly a normal SQL-based relational database, but more of a javascript-based object oriented one. Ever seen this type of data before?
key: "value"
That's what we're working with, and it's great for simple applications like the Movie PWA I was building.
Right out the box the API works by events, but I recommend ditching that and instead installing Jake Archibald's 'IndexedDB Promised Library', which pretty much mirrors the API, and uses... you guessed it. Promises.

Disclaimer

Many tutorials like the one by Google, use an old version of the library, and will not work if you follow it. Ask me how I figured that out.

To understand how IndexedDB works, you first need to know the different ways of handling data therein.
Before anything can be done, the database has to be 'opened'. I'm putting that in quotes, because you actually also need to 'open' it to create it, so you're kind of doing both at the same time.
The way you'll probably see it imported in online tutorials is like this:

import idb from 'idb';
Enter fullscreen mode Exit fullscreen mode

You would use it like idb.open()
but since becoming a module we're instead required to import it like so:

import { openDB } from 'idb';
Enter fullscreen mode Exit fullscreen mode

Highest Level

To start the whole process we'll open/create the actual database
For that create an async function somewhere and write this inside.

async function myDatabase() {
   const db = await openDB('Database_name', 1, {

   });
}
Enter fullscreen mode Exit fullscreen mode

This is the highest level of the database.
You can create as many as you want, but usually there's only one of these per app.

The Object Store

This is one of the buckets that we're gonna store our data in, it's like a table in traditional relational databases.

const db = await openDB('Database_name', 1, {
   upgrade(db) {
     const store = db.createObjectStore('name_of_store', {
        keyPath: "id_of_the_thing"
     });
   }
});
Enter fullscreen mode Exit fullscreen mode

We need the upgrade if this version of the database hasn't been opened before, which it hasn't... I don't think.
Honestly I would look this up if you need to, because the methods of IndexedDB are quite weirdly named and you might not need it in your project. But for the sake of not breaking mine, I'm keeping it for now.

Inside of that, we're creating the store, also called a bucket, or table. Well, It's where we store our data. Ha.
If your project breaks, or you need a random ID for your stuff, add an autoIncrement like this:

const store = db.createObjectStore('name_of_store', {
   keyPath: "id_of_the_thing",
   autoIncrement: true
});
Enter fullscreen mode Exit fullscreen mode

Test time!

Whenever or however you call your async function, an IndexedDB should show up in your browsers dev tools. You'll find it in the application tab, right next to localStorage.
image
Cool. We have a database, and a store/bucket/table ready to receive our stuff.

To add our first item to the store, stay inside our async function, and write like so:

await db.add('name_of_store', {
   apple: "delicious"
});
Enter fullscreen mode Exit fullscreen mode

And in the browser:
image
We have our first piece of data!

But... how do you get the thing back you ask?

var myThing = await db.get('name_of_store', 1)
Enter fullscreen mode Exit fullscreen mode

The 1 is the id of our apple in the store. If you specified it to be something specific instead of an auto incremented one, you of course use that instead.
The variable myThing now has an object ready to be used!
image

Full code

async function myDatabase() {
   // It's a good idea to have this error handling just in case
   if (!('indexedDB' in window)) {
      console.log('This browser doesn\'t support IndexedDB');
      return;
   }

   const db = await openDB('Database_name', 1, {
      upgrade(db) {
        const store = db.createObjectStore('name_of_store', {
           keyPath: "id_of_the_thing",
           autoIncrement: true
        });
      }
   });

   await db.add('name_of_store', {
      apple: "delicious"
   });

   var myThing = await db.get('name_of_store', 1);

   console.log(myThing);
}
Enter fullscreen mode Exit fullscreen mode

So that kind of ends this simple setup.
It's incredible how little help you're able to find online regarding all of this, so hopefully this will help myself in the future, and maybe some lost soul will stumble upon it as well.
There's loads of other features that can be used, but I won't get into that right now.
You can find more examples on Jake Archibald's library readme:
https://github.com/jakearchibald/idb

💖 💪 🙅 🚩
thorwurtzner
Thor Würtzner

Posted on August 18, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

The modern way of setting up IndexedDB