Getting object store already exists inside onupgradeneeded
Isn't the createObjectStore operating on a new version of the database which is empty?
When you get upgradeneeded
the database is in whatever state you left it in before. Since you don't know what versions of your code a user will have visited, you need to look at the event's oldVersion
to find out what that was. The typical pattern is something like this:
var rq = indexedDB.open('db', 5);
rq.onupgradeneeded = function(e) {
var db = rq.result;
if (e.oldVersion < 1) {
// do initial schema creation
db.createObjectStore('users');
}
if (e.oldVersion < 2) {
// do 1->2 upgrade
var s = db.createObjectStore('better_users');
s.createIndex('some_index', ...);
db.deleteObjectStore('users'); // migrating data would be better
}
if (e.oldVersion < 3) {
// do 2->3 upgrade
rq.transaction.objectStore('better_users').createIndex('index2', ...);
}
if (e.oldVersion < 4) {
// do 3->4 upgrade
db.createObjectStore('messages', ...);
}
if (e.oldVersion < 5) {
// do 4->5 upgrade
// ...
}
}
I am curious why the version number is different in the summary line and when expanded.
That one is subtle... I believe at the point where the 5
was logged the database had started the upgrade. But because an exception was thrown in the upgradeneeded
handler the upgrade was aborted, and the version number was rolled back to 4
before the details were logged.
The best way to upgrade the DB is checking if the store name is already there. In this example I'm using https://npmjs.com/idb
openDB('db-name', version, {
upgrade(db, oldVersion, newVersion, transaction) {
if(!db.objectStoreNames.contains('messages')) {
db.createObjectStore('messages', { keyPath: "id", autoIncrement: true })
}
}
})
If you need to check if an indexName already exist, you can get the objectStore and check for the indexNames property if it contains the indexName you need.
openDB('db-name', version, {
upgrade(db, oldVersion, newVersion, transaction) {
const storeName = transaction.objectStore('storeName')
if(!storeName.indexNames.contains('indexName')) {
storeName.createIndex('indexName', 'propertyName', { unique: false });
}
}
})
Using indexDB API with indexNames and objectStoreNames to check if something is either there or not makes my code way more reliable and easy to maintain, it is also briefly mentioned on Working with IndexDB Using database versioning