javascriptindexeddb

Create multiple stores in IndexedDB and get notification when all are available


I am new to IndexedDB and trying to create a database with many stores in it.
After creating the stores my app can go ahead and add records to it, but I need to be sure that all stores have been created.

I am using this function to do so:

function createDatabase() {
   return new Promise((resolve, reject) => {
      const dbOpenRequest = window.indexedDB.open('GHCaching', 14);

      dbOpenRequest.onupgradeneeded = (event: any) => {
         const db = event.target.result;

         if (!db.objectStoreNames.contains('myTestStore1')) {
            const suppliersObjectStore = db.createObjectStore('myTestStore1', { keyPath: 'ssn' });
            suppliersObjectStore.transaction.oncomplete = () => {
               //First was created
            };
         }

         if (!db.objectStoreNames.contains('myTestStore2')) {
            const customersObjectStore = db.createObjectStore('myTestStore2', { keyPath: 'ssn' });
            customersObjectStore.transaction.oncomplete = () => {
               //Second was created
            };
         }
      };

      dbOpenRequest.onsuccess = (event: any) => {
         const db = event.target.result;
         console.log('Database opened successfully.');
         resolve('success');
      };

      dbOpenRequest.onerror = (event: any) => {
         console.error('Error creating database:', event.target.error);
         reject(event.target.error);
      };
   });
}

I would expect the dbOpenRequest.onsuccess to be fired only after both stores have been created successfuly.
However, //First was created, is NEVER called at all.

How can I create multiple stores in the beginning and get a callback that fires only after all stores have been created?


Solution

  • One small improvement is to review how event listeners work.

    Try changing store.transaction.oncomplete = to store.transaction.addEventListener('complete' , function (event) { ... }).

    When setting oncomplete, this effectively removes all other listeners and just sets one listener. If you set oncomplete twice in a row, only the second listener is registered because the second assignment to oncomplete removes (well, it overwrites) the first. But if you use addEventListener, then the first remains even when you add the second.

    Next, you do not really need to listen to when the version change transaction completes. It is the same transaction for both stores, so you are listening redundantly. There is not a transaction per createObjectStore. Both use the same transaction. So listening twice is redundant. Then, the fact that the success event eventually fires is already an indicator the version change transaction completed, so listening for the version change transaction to complete is in general kind of pointless.