Today many ways exist to store data inside a browser. What started with cookies has now evolved to very comprehensive storage mechanisms. Web Storage (LocalStorage/SessionStorage) is a key-value store which can hold up to 5MB of data. Web SQL brings SQL to the frontend and can store significantly more data. Although WebSQL is widely supported, the W3C dropped support because it was not a standard, but an implementation of SQLite.
The alternative for Web SQL is the Indexed Database API (IndexedDB), developed by the Mozilla foundation, a NoSQL database which stores key-values. The values can be complex structured objects and keys can be properties of those objects.
Below we will explore this next-gen storage mechanism where I will show how to persist this ‘customerData’ object
Please note that at this moment firefox is the only browser fully supporting all the specs of IndexedDB.
To setup a connection with an IndexedDB database you have to use the IndexedDB object. However, it is still an experimental feature and therefore hidden under browser prefixes. The following code snippet shows how to setup a connection and which events to listen to
Binding to these events is necessary, because this process is asynchronous. The onupgradeneeded event is special and is only fired when the database is created or the version number has changed. Inside this function you can create/modify the tables, which are called ‘object stores’. For the ‘customerData’ object we could create the following object store
‘ssn’ and ’email’ should be unique, and with the keyPath option the ‘ssn’ value is used as the key. Indices are useful because they can be used for searches.
Within a transaction you can read from, write to and delete entries from an object store. Furthermore a transaction has a scope: the objects stores it applies to, and a mode: read only or read-write. So, to write the customerData to the customers store do
An entry lookup by its key value is equally simple
Instead of using the event.target.result you can use dbconn.result, which is useful when performing any of these actions outside the dbconn.onsuccess function.
Using an index is basically identical to a lookup by its key value. The only practical difference is that an index doesn’t have to be unique, in which case the entry with the lowest key value is returned
With a cursor you can retrieve one or more entries. For example, if the above example would normally return multiple entries a cursor could be used as follows
With the IDBKeyRange you can also define a lower and upper bound, which allows you to retrieve a range of entries
To get an idea about the performance I have written a performance test for WebSQL and IndexedDB. Testing with 500000 entries the only noticable difference is that IndexedDB is a lot faster with inserts. This is because it builds its indices afterwards. Only during this period the performance is not very good, but when this process is finished, it performs equally well as WebSQL.
IndexedDB is a very robust and well performing alternative to WebSQL, but unfortunately still experimental. The fact that Firefox and Internet Explorer have no plans to support WebSQL, will speed up the adoption of IndexedDB.