IndexedDB: one-to-many relation - How?

I am trying to find the best approach to work with one to many relations and indexedDB.

By one to many I mean relations between object stores. E.g.

Object store: artists:
and
Object store: albums
(and maybe another level
Object store: songs)

Can anyone point to guideline for how this is best done?

Is one of the indexedDB wrappers the answer to do this in a simple way?

Thanks

Well, for starters, indexedDB itself has no relations. So whatever you do, you get to do the hooking up yourself. You could have object stores that you then join on IDs, that’s what I do. Have an array of IDs and map that to values in the other store.

@freaktechnik

Thanks Martin. Do you have an implemented example of your approach?

Any opinions on IndexedDB wrappers?

I have my own wrapper. It looks a bit like this: https://github.com/freaktechnik/justintv-stream-notifications/blob/master/src/database-manager.js

The matching is just the matching array operation. In the simplest case it’s a map, but usually I implement it the other way. Get too many of the potential matches for the IDs in the array and then filter them down. But you could also do that while going through an index (possibly limited with a https://developer.mozilla.org/en-US/docs/Web/API/IDBKeyRange so you don’t have to go through everything etc.)

Some Promise based wrapper is definitely handy. I wrote my own as well :slight_smile: but it’s very simple one:

async function dbTransaction(tableName: DB_TABLE, transactionMode: IDBTransactionMode) {
  const db = await _dbPromise;
  return db.transaction([tableName], transactionMode).objectStore(tableName);
}

async function dbOperation<T>(transaction: IDBObjectStore | IDBIndex, fnName: KeysOfType<IDBObjectStore & IDBIndex, Function>, ...params: any[]): Promise<T> {
  return new Promise((resolve, reject) => {
    // @ts-ignore - I'm not sure this can be done "by the book" without loosing the flexibility
    const idbRequest = transaction[fnName].apply(transaction, params);
    idbRequest.onerror = reject;
    idbRequest.onsuccess = () => {
      resolve(idbRequest.result)
    };
  })
}

async function dbTransactionOperation<T>(tableName: DB_TABLE, transactionMode: IDBTransactionMode, fnName: KeysOfType<IDBObjectStore & IDBIndex, Function>, ...params: any[]) {
  return dbOperation<T>(await dbTransaction(tableName, transactionMode), fnName, ...params)
}

It’s in TypeScript, but you can just remove types and it will work fine. Using these functions you can then easily query all your data with Promises.

Also as a user of IndexedDB, make sure to vote for some bugs! :smiley:

https://bugzilla.mozilla.org/show_bug.cgi?id=944918 (this one is 6 years old!)
https://bugzilla.mozilla.org/show_bug.cgi?id=1522188
https://bugzilla.mozilla.org/show_bug.cgi?id=1478602

Do anyone have opinions / experience with https://dexie.org/

It seems to be the goto wrapper.