rob
rob

Reputation: 18523

Asynchronously update IndexedDB in upgrade event

In the onupgradeneeded() event for IndexedDB I am trying to update each record in an object store. In order to update them I need to first preform an async operation but this causes the upgrade transaction to become inactive and I get the error

Failed to execute 'update' on 'IDBCursor': The transaction is not active.

In the follow code I am simulating an async operation with setTimeout()

let openRequest = indexedDB.open('myDb', 1);

openRequest.onupgradeneeded = function (versionEvent) {
    let db = versionEvent.target['result'];
    let upgradeTransaction = versionEvent.target['transaction'];

    if(versionEvent.oldVersion < 1) {
        let objStore = db.createObjectStore('sample');
        objStore.add('one', '1');
        objStore.add('two', '2');
    }

    if(versionEvent.oldVersion >= 1) {
        let getCursor = upgradeTransaction.objectStore('sample').openCursor();

        getCursor.onsuccess = (e) => {
          let cursor = e.target['result'];
          if (cursor) {
            setTimeout(() => {
              cursor.update(cursor.value + ' updated');
              cursor.continue();
            })
          }
        }
    }
};

https://plnkr.co/edit/DIIzLduZT1dwOEHAdzSf?p=preview

If you run this plunker it will initialize IndexedDB. Then if you increase the version number to 2 and run it again you will get the error.

How can I update IndexedDB in an upgrade event if my update relies on an async operation?

Upvotes: 6

Views: 717

Answers (1)

Joshua Bell
Joshua Bell

Reputation: 8365

You need a different approach. Options include:

  • Making the schema changes immediately, but deferring adding new data for a subsequent transaction.
  • Fetch the data before trying to perform the upgrade. Since fetching the data is slow this is likely not desirable.
  • Conditionally fetch the data, only if an upgrade is needed.

There are two approaches for the latter. You could do an open() with no version number, check the version, and then fetch/upgrade if it is lower than desired. Or you can open at the new version and in upgradeneeded abort the upgrade (get the transaction from the request and call abort() on it) then fetch the data and re-attempt the upgrade.

Upvotes: 7

Related Questions