Check if IndexedDB database exists
Asked Answered
S

10

36

Is there a way to check if an IndexedDB database already exists? When a program tries to open a database that does not exists the database is created. The only way that I can think of is something like the following, where I test if an objectStore already exists, if it doesn't, the database is deleted:

var dbexists=false;
var request = window.indexedDB.open("TestDatabase");
request.onupgradeneeded = function(e) {
    db = e.target.result;
    if (!db.objectStoreNames.contains('todo')) {
       db.close();
       indexedDB.deleteDatabase("TestDatabase");
    } else {
       dbexists=true;
    }
}
Sacramentarian answered 4/7, 2013 at 11:19 Comment(0)
P
25

In the onupgradeneeded callback you can check the version. (e.target.result.oldversion). If it is 0, the db didn't exist.

Edit: After some investigation. You can't be 100% sure if a new db is created. One thing I am sure of is the fact that you can only work with an indexeddb if it has a version 1 or higher. I believe that a db can exist and have a version 0 (The only fact is you can't work with it and the onupgradeneeded event will be called).

I have build my own indexeddbviewer. In that I open the indexeddb without version and if I come in to the onupgradeneeded event, that means the db doesn't exist. In that case I call the abort so it doesn't upgrade to a version 1. This is the way I check it.

var dbExists = true;
var request = window.indexeddb.open("db");
request.onupgradeneeded = function (e){
    e.target.transaction.abort();
    dbExists = false;
}

but as mentioned. It is possible that the db will continue to exist in that case, but the onupgradeneeded will always be called

Painty answered 4/7, 2013 at 15:32 Comment(13)
It's a good idea. But I still have to delete the database afterwards, if I only want to check if the database exists. There should be a method to test if the database exists.Sacramentarian
Call the abort method on the transaction. E.target.result.abort()Painty
Are you sure you meant (e.target.result.db.version)? Shouldn't it be (e.target.result.version) or (db.version), after (db = e.target.result;)? And I think after the database is created the version is 1, not 0.Sacramentarian
Perhaps you meant the oldVersion attribute, but it isn't supported in most browsers.Sacramentarian
Regarding the abort method, how do you use it inside the request.onupgradeneeded event hander? If use e.target.result.abort() I get the following error: Object #<IDBDatabase> has no method 'abort'Sacramentarian
You are right. The abort needs to be called on the transaction and you should find that on e.target.transaction.abort(). And as you mentioned I meant the oldVersion, but if that doesn't exist and the version is 1 in the onupgradeneeded event, you can be pretty sure it's a new db. But I was wondering, why would you want to only check if a db exists?Painty
I'm doing an offline app, and if a local DB exists that means the user has already "loaded" the application and created the database. If the local DB does not exist he must log in to the server to start the "installation" process.Sacramentarian
It works. Thank you Kristof for your help. As a "side effect", an AbortError is thrown and it can be catched by a "request.onerror" event handler. I thought I could use the "request.onabort" event handler but it isn't triggered.Sacramentarian
Try catching it on the transaction objectPainty
Add e.target.transaction.onabort=function() {, and it works, Thank you Kristof for remembering that possibility.Sacramentarian
For more information on when the onupgradeneeded event fires see this article: developer.mozilla.org/en-US/docs/Web/API/… it only gets fired when there has never been a db before or the user specifies a different version number from any db that exists.Annelid
In Chrome 37, e.target.result.oldversion does not exists. Instead, I had to use e.oldVersion . This is mentioned here: w3.org/TR/IndexedDBErnaldus
window.indexeddb.open("db") request does not contain transaction object... req.transaction == nullBaeda
P
20

With ES6 you can find an IndexedDB database by its name using the following code:

const dbName = 'TestDatabase';
const isExisting = (await window.indexedDB.databases()).map(db => db.name).includes(dbName);

Pantia answered 12/12, 2019 at 16:29 Comment(2)
Thanks! This seems like a surefire way to do it (at least on Chrome) and doesn't suffer from the issue identified by the OP and that other answers suffer from ("When a program tries to open a database that does not exists the database is created"). (BTW,I think your const isExiting should be const isExisting ;) )Flaky
Sadly indexedDB.databases is not available in Firefox :(Hardness
G
8

The following code works. I have tested it with Chrome, IE and Opera. Tested with both locally open databases and closed and with databases of different versions, so it should be accurate. The creation/deletion of the database is needed. However, it will be an atomic operation with no risk for race conditions because the spec promises to not launch to open requests in parallell if the open request results in a database creation.

function databaseExists(dbname, callback) {
    var req = indexedDB.open(dbname);
    var existed = true;
    req.onsuccess = function () {
        req.result.close();
        if (!existed)
            indexedDB.deleteDatabase(dbname);
        callback(existed);
    }
    req.onupgradeneeded = function () {
        existed = false;
    }
}

To use the function, do:

databaseExists(dbName, function (yesno) {
    alert (dbName + " exists? " + yesno);
});
Gossett answered 20/5, 2014 at 10:0 Comment(1)
Wtf? Why are you deleting the database if it existed? We are testing if it exists, we don't want to delete it if so. Shouldn't it be if (!existed) indexedDB.deleteDatabase(dbname); ???Baeda
B
5

I spent more than an hour playing with it and basically the only deterministic and reliable way to do that is using webkit's webkitGetDatabaseNames.

There is literally like 10 ways to test if DB exists using onupgradeneeded, but that just doesn't work in production. It got either blocked for several seconds, sometimes completely on deleting database. Those tips to abort transaction are nonsense because window.indexeddb.open("db") request does not contain transaction object... req.transaction == null

I can't believe this is real...

Baeda answered 5/12, 2014 at 23:21 Comment(1)
The request does have a transaction within a handler for an upgradeneeded event.Perlite
D
2

This function checks if the database exists. Use the onupgradeneeded event, if the version is 1 and the event is triggered, it means that the database does not exist, but is created with the window.indexedDB.open(name) function, which means that you should remove it.

When the onsuccess event fires, but not the onupgradeneeded event (Variable dbExists remains true) indicates that the database existed before and returns true.

/**
 * Check if a database exists
 * @param {string} name Database name
 * @param {function} callback Function to return the response
 * @returns {bool} True if the database exists
 */
function databaseExists(name, callback) {
  var dbExists = true;
  var request = window.indexedDB.open(name);
  request.onupgradeneeded = function (e) {
    if (request.result.version === 1) {
      dbExists = false;
      window.indexedDB.deleteDatabase(name);
      if (callback) callback(dbExists);
    }
  };
  request.onsuccess = function (e) {
    if (dbExists) {
      if (callback) callback(dbExists);
    }
  };
}

The output of the function is through a callback function. The form of use is as follows:

var name = "TestDatabase";

databaseExists(name, function (exists) {
  if (exists) {
    console.debug("database " + name + " exists");
  } else {
    console.debug("database " + name + " does not exists");
  }
});

[sorry for my english]

Diaphony answered 23/3, 2014 at 22:51 Comment(0)
T
2
function databaseExists(name) {
  return new Promise(function (resolve, reject) {
    var db = indexedDB,
      req;

    try {
      // See if it exist
      req = db.webkitGetDatabaseNames();
      req.onsuccess = function (evt) {
        ~[].slice.call(evt.target.result).indexOf(name)
          ? resolve(true)
          : reject(false);
      };
    } catch (e) {
      // Try if it exist
      req = db.open(name);
      req.onsuccess = function () {
        req.result.close();
        resolve(true);
      };
      req.onupgradeneeded = function (evt) {
        evt.target.transaction.abort();
        reject(false);
      };
    }
  });
}

Usage:

databaseExists("foo").then(AlreadyTaken, createDatabase)
Talmud answered 6/9, 2015 at 13:19 Comment(2)
webkitGetDatabaseNames has been deprecated in chrome 60Kiwanis
Yes, webkitGetDatabaseNames cannot be used now. But see Benny Neugebauer's answer below for its replacement.Flaky
E
2

Here is a async util function returns true false to check if a db exist with given name and version.

const indexedDBUtil = {
    dbExist: async(dbName: string, version = 1)=> {
        let newDb = false;
        await ((): Promise<void>=>{
            return new Promise((resolve, reject)=>{
                const req = indexedDB.open(dbName, version );
                req.onupgradeneeded = ()=>{
                    req.transaction.abort();
                    newDb = true;
                    resolve();
                }
                req.onsuccess = () => {
                    resolve();
                }
            });
        })();
        
        return newDb;
    }
}
Eindhoven answered 28/3, 2022 at 10:45 Comment(0)
M
1

If you are using alasql you could use something like:

async existsDatabase(myDatabase) {
    return !(await alasql.promise(`
        create indexeddb database if not exists ${myDatabase};
    `));
}

This will create the database if it not exists but it was the best solution that I've found until now so far. You can delete the database if it exists with a similar query too: drop indexeddb database if exists ${myDatabase};

Mackenzie answered 18/1, 2019 at 13:38 Comment(0)
R
0

Another way to do this (on Chrome but not Firefox) is with an async function as follows:

/**
 * Checks the IndexedDB "web-server" to see if an specific database exists.
 * Must be called with await, for example, var dbFound = await doesDbExist('mySuperDB');
 * @param {string} dbName The database name to look for.
 * @returns {boolean} Whether a database name was found.
 */
async function doesDbExist(dbName) {
    var result = await indexedDB.databases();
    var dbFound = false;
    for (var i = 0; i < result.length && !dbFound; i++) {
        dbFound = result[i].name === dbName;
    }
    return dbFound;
}

Then just call the function as follows:

var dbFound = await doesDbExist('mySuperDB');
Rickety answered 8/11, 2019 at 21:9 Comment(4)
indexedDB.databases is not a function on FirefoxOsteoclast
Sorry, I should had specified that this is for Chrome.Rickety
Can you point me to where I can find what browsers support the "databases" function? I didn't find that level of granularity at caniuse.com.Thurmanthurmann
You can find the information at Browser compatibility @ThurmanthurmannRickety
G
-1

Hi i know this question is already answered and accepted , but i think one of the good way to do it like this

var indexeddbReq = $window.indexedDB.webkitGetDatabaseNames();
                indexeddbReq.onsuccess = function(evt){
                    if(evt.target.result.contains(
                       // SUCCESS YOU FOUND THE DB
                    }
                    else{
                       // DB NOT FOUND
                    }
                }
Guffaw answered 12/7, 2015 at 13:16 Comment(1)
Please correct the malformed code. Then I will vote up again.Gerontology

© 2022 - 2024 — McMap. All rights reserved.