How to create multiple object stores in IndexedDB
Asked Answered
E

3

14

I don't know if I'm right or wrong. But as I know I can't create a version change transaction manually. The only way to invoke this is by changing the version number when opening the indexed DB connection. If this is correct, in example1 and example2 new objectStore will never be created?

Example1

function createObjectStore(name){
    var request2 = indexedDB.open("existingDB");    
    request2.onupgradeneeded = function() {
        var db = request2.result;   
        var store = db.createObjectStore(name); 
    };
}

Example2

function createObjectStore(name){
    var request2 = indexedDB.open("existingDB");    
    request2.onsuccess = function() {
        var db = request2.result;   
        var store = db.createObjectStore(name); 
    };
 }

Example3 - This should work:

function createObjectStore(name){
    var request2 = indexedDB.open("existingDB", 2);     
    request2.onupgradeneeded = function() {
        var db = request2.result;   
        var store = db.createObjectStore(name); 
    };
}

If I want to create multiple objectStore's in one database how can I get/fetch database version before opening the database?? So is there a way to automate this process of getting database version number??

Is there any other way to create objectStore other than that using onupgradeneeded event handler.

Please help. Thanks a lot.

Edit:

Here is same problem that I have: https://groups.google.com/a/chromium.org/forum/#!topic/chromium-html5/0rfvwVdSlAs

Excide answered 20/11, 2013 at 13:46 Comment(0)
T
25

You need to open the database to check it's current version and open it again with version + 1 to trigger the upgrade.

Here is the sample code:

function CreateObjectStore(dbName, storeName) {
    var request = indexedDB.open(dbName);
    request.onsuccess = function (e){
        var database = e.target.result;
        var version =  parseInt(database.version);
        database.close();
        var secondRequest = indexedDB.open(dbName, version+1);
        secondRequest.onupgradeneeded = function (e) {
            var database = e.target.result;
            var objectStore = database.createObjectStore(storeName, {
                keyPath: 'id'
            });
        };
        secondRequest.onsuccess = function (e) {
            e.target.result.close();
        }
    }
}
Telescope answered 20/11, 2013 at 20:19 Comment(6)
Thanks for reply. This could work. But it seems "stupid" to me and not programmatic way to open database twice :/Excide
Maybe there is really no other way to do it...I'll wait a day and see. IndexedDB seems still very unfinished and some things are done pretty bad.Excide
I don't understand why you want to know the version of the db upfront? you know in wich version you need to open the database. if the version doesn't match the version on the you provided it wil give you a way to upgrade your database. In that event you will know from which version you need to upgrade.Spree
Knowing the version upfront doesn't work every time, especially if the database can update often (new indexes, tables), but reading the database version on the first opening and storing it in cache could work whenever upgrade is needed, that way you can avoid the extra db open for reading the version.Telescope
I know scheme's can change, but as developer of the application you choose which indexes and tables you want, not the user that is using the application. Another solution is like you shown, but with this in mind that depending on the client the indexeddb will defferSpree
This was made to be overly complicated. The reps from W3C obviously sent there worst designers to come up with this mess.Engrossment
S
5

The only way you can create an object store is in the onupgradeneeded event. You need a version_change transaction to be able to change the schema. And the only way of getting a version_change transaction is through a onupgradeneeded event.

The only way to trigger the onupgradeneeded event is by opening the database in a higher version than the current version of the database. The best way to do this is keeping a constant with the current version of the database you need to work with. Every time you need to change the schema of the database you increase this number. Then in the onupgradeneeded event, you can retrieve the current version of the database. With this, you can decide which upgrade path you need to follow to get to the latest database schema.

I hope this answers your question.

Spree answered 20/11, 2013 at 14:11 Comment(7)
Thanks for your response.It is all clear to me what you wrote, but where will I store that constant? If I close browser and open it again then that constant is lost, Am I'm right?!? And then, when I want to create new object how will I know which version of database I have? Thanks.Excide
No if you just define var constant=3; it will stay the same everytime you open the file. When you need a newer version you just set it to 4 for exampleSpree
I have small app, and every time i upload a file new objectStore needs to be created. I'm a bit confused now, can you please explain further or give small example. If i have constant var version = 2; and then I have automatic upload of 100+ files. So that means 100+ objectStores needs to be created. What is then a proper way to do it?Excide
if you have var const = 3; lets say X files are uploaded 1 by 1, and lets say number version is now X. Close browser, open browser again, You have const =3; and how will You now database version? It seems to me that Deni Mf is right, Caching is needed. But that is not permanent storage either.Excide
Why would tou need a new object store for a file? you can stor multiple files in only 1 object store. For adding data you don't need to change the schemeSpree
Because I'm building a torrent client. Each file name is object store and file is split in blobs and stored inside object store. If you think there is some better way to do it please inform me. Thanks.Excide
Ok, now I follow. I think Deni's solution is the way To Go. Opening the db bydefault without a Version and reopen It with An incremented Version for ever fileSpree
E
0

The accepted answer is wrong or deprecated. Here's how I got it to work. Apologies, a bad design necessitates bad code:

  getStore(name: string, version: number = 1): Promise<IDBObjectStore> {

    let dbRequest = indexedDB.open("hydraLocalDatabase", version);
    let store: IDBObjectStore;
    let promise = new Promise<IDBObjectStore>((resolve, reject) => {

    dbRequest.onsuccess = (e2) => {
      let dbRequest2 = <IDBOpenDBRequest>e2.target;
      let db2 = dbRequest2.result;

      if (version > this.lastVersionAttempted) {

        if (db2.objectStoreNames.contains(name)) {

          try {
            var transaction2 = db2.transaction([name], 'readwrite');
            store = transaction2.objectStore(name);
            resolve(store);
          }
          catch (e) {
            this.logger.fatal(e);
            reject(e);
          }
        }
      }
      else {
        version = db2.version;

        db2.close();
        dbRequest2 = indexedDB.open("hydraLocalDatabase", version + 1);

        dbRequest2.onupgradeneeded = (e3) => {
          let dbRequest3 = <IDBOpenDBRequest>e3.target;
          let db3 = dbRequest3.result;
          let transaction: IDBTransaction;

          if (!db3.objectStoreNames.contains(name)) {
            try {
              store = db3.createObjectStore(name, { keyPath: 'id' });
              transaction = dbRequest3.transaction;

              transaction.oncomplete = (e4) => {
                try {
                  var transaction4 = db3.transaction([name], 'readwrite');
                  store = transaction4.objectStore(name);
                  resolve(store);
                }
                catch (e) {
                  this.logger.fatal(e);
                  reject(e);
                }
              }
            }
            catch (e) {
              this.logger.fatal(e);
              reject(e);
            }
          }
        }

        dbRequest2.onerror = (e) => {
          reject(e);
        }
      }
    }

    dbRequest.onerror = (e) => {

      this.lastVersionAttempted = version;

      this.getStore(name, version + 1).then((s) => {
        resolve(s);
      }, (e) => {
        reject(e);
      });
    }
  });

  return promise;
}
Engrossment answered 4/5 at 15:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.