HTML 5 Indexed DB API: HTML 5 has a very good technology known as Indexed DB which is client-side data storage for each domain. This means the HTML5 application can work with the database without having a server. This IndexedDB was introduced by W3C to replace WebSQL.
HTML 5 Indexed DB API
Difference between IndexedDB and LocalStorage in HTML5
In case if you already know the client-side storage which is known as LocalStorage.If you are new to both the Local Storage and Indexed DB because storing data on the client-side is the same. There are two major differences between Local Storage and IndexedDB, one is storing data in string format in key-value format and another one is can store entire objects in object-store.
The Local Storage has an embedded table with two columns which are id and string format value. The IndexedDB has an engine that allows having many tables. So, the IndexedDB is best for the complex data structures. Some other differences in these API’s may affect the implementation of our applications in one way or the other. Most of the times we consider the major differences that we discussed earlier.
Some features of IndexedDB
IndexedDB allows many databases and storage for everyone. Each database has a name and version number which helps to identify them. We can upgrade the database version which changes the structure of the database.
IndexedDB is NOT SQL
This is not a feature but has to consider because to avoid misunderstanding. The Indexed DB is not an SQL DB. In IndexedDB no need to describe the structure like SQL database.
HTML5 IndexedDB API is asynchronous
This is the most important feature in Indexed DB because the request we ask for opening a database is non-blocking. Let’s see an example
Example to Open Database
request = indexedDB.open('database'); database = request.result;
Here, it is invalid because the IndexedDB cant is used like this. The correct method is mentioned below.
The correct method to Open Database in Indexed DB API
request = indexedDB.open('database');request.onsuccess = function() { database = request.result;// Now we can perform database operations. }
HTML5 Indexed DB API Usage
Let’s see the clear concepts of usage of IndexedDB
Creating the Database
At first, we have to retrieve the IndexedDB object then request for the opening database with name and version.(a version is optional). In this example, we have DB(database) with a list of products that have information like name, description, price etc.
Creating the Database Example
indexeddb.js
DATABASE_NAME = 'catalog'; DATABASE_VERSION = 1; STORE_NAME = 'product'; var database; var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedBD || window.msIndexedDB; var request = indexedDB.open(DATABASE_NAME, DATABASE_VERSION); To get the indexedDB object, we will arrange many fallbacks for every search engine.After requesting the database we must bind the function onupgradeneeded event which creates database or upgrade the version. indexeddb.js request.onupgradeneeded = function() { console.log('Database upgrade/creation.'); database = request.result; var catalogStore = database.createObjectStore( STORE_NAME, { keyPath: 'id', autoIncrement: 'true' } ); catalogStore.createIndex('by_id', 'id'); catalogStore.createIndex('by_name', 'name'); console.log('The database has been created/updated.'); }
As mentioned earlier the first thing we must do is retrieve the database which is request object retrieved from IndexedDB object. Now we have to create the store for catalog with the help of the createObjectStore method.
This first parameter is the name of the store which is mandatory but the next one is options.
- Keypath: Keypath is the “primary key” of the storage.
- AutoIncrement: This property is used to make keypath property increment automatically for the newly inserted objects and no need to consider to provide value.
In case if you have created a primary key you can also create an index that gives permissions to access. With the help of creating the index method, we have created both name and id parameters, the name parameter is used to retrieve the data and other parameters are the property it corresponds to. Unless you change the database version all these statements will execute.
Inserting Data
In the database we can insert data at creation time or later, you can also create inside the onupgradeneeded scope then no need to declare explicitly.
Inserting Data Example
indexeddb.js
function insertInitialData(catalogStore) { catalogStore.put({ 'name': 'A product', 'description': 'Description of a product.', 'price': 10, }); catalogStore.put({ 'name': 'Another product', 'description': 'Description of another product.', 'price': 20, 'subproduct': { 'name': 'Subproduct of a product' } }); }request.onupgradeneeded = function() { // After creating the object storage and indexes... insertInitialData(catalogStorage);// ... }
NOTE: Here we are just inserting raw objects with properties that have not described in storage definition. In case you are using SQL then it may be quite confusing but we can insert objects without considering the properties. With the help of developer tools for the database, we can observe its data and structure.
The following image describes the database and data with chromium developer tools.
Visualizing database data with Chromium developer tools
In case you want to insert data after the creation, we can do it onupgradeneeded scope. Another event onsuccess which is triggered after creating/updating the database successfully. Let’s see an example by inserting some values.
Insert values to Database Example
indexeddb.js
request.onsuccess = function() { console.log('Successful request for IndexedDB.'); database = request.result; var transaction = database.transaction(STORE_NAME, 'readwrite'); var catalogStore = transaction.objectStore(STORE_NAME); var moreData = [ { 'name': 'A third product', 'description': 'Description of a third product.' }, { 'name': 'Yet another product', 'description': 'One last product.' } ];moreData.forEach(function(data) { catalogStore.put(data); });transaction.oncomplete = function() { console.log('Transaction completed successfully.'); }transaction.onerror = function(error) { console.log('An error occurred during the transaction: ' + error); } }
After database request, we first create a transaction for the given store which exists in the database. If you are inserting data then the transaction will provide write access bypassing read-write value as the second parameter. Here in this transaction, we get storage objects with the help of the put method we insert the data. there are handlers that specify th success, failure, transactions that define oncomplete and onerror events.
In case if you want to insert several objects in a single transaction and any one of the transition fails then rollback will happen immediately.
Retrieving Data
The basic steps to retrieve data is the same as inserting the data. at first, we have to create transaction later we get storage from it. With the storage, we can retrieve the information by making a “query” and making the request to this index.
Retrieving Data Example
indexeddb.js
function query() { var transaction = database.transaction(STORE_NAME, 'readonly'); var catalogStore = transaction.objectStore(STORE_NAME); var idIndex = catalogStore.index('by_id'); var nameIndex = catalogStore.index('by_name'); var request = idIndex.get(1); request.onsuccess = function() { console.log(request.result); } var request2 = nameIndex.get('Another product'); request2.onsuccess = function() { console.log(request2.result); } }
Here we made different requests on different indexes to see how the indexes are working and with the help of onsuccedd event, the API is asynchronous.
Because of this reason, we created other requests in case we use the first request object we get an exception like ” The request has not finished”.The result should be like following
Object { name: "A product", description: "Description of a product.", price: 10, id: 1 } Object { name: "Another product", description: "Description of another product.", price: 20, subproduct: Object, id: 2 }
Cursors in IndexedDB
IndexedDB will support cursors which are very easy. The following example will show all the elements in the storage.
Cursors in IndexedDB Example
function queryWithCursor() { var transaction = database.transaction(STORE_NAME, 'readonly'); var catalogStore =transaction.objectStore(STORE_NAME); catalogStore.openCursor().onsuccess = function(event) { var cursor = event.target.result; if (cursor) { console.log(cursor.value); cursor.continue(); } } }
Summary
The above example shows the usage of HTML5 IndexedDB, which is used for storing data on the client-side. At first, IndexedDB is not the option for storing data on the client-side that’s why we have compared with LocalStorage. We have a deal with IndexedAPI like creating the database, inserting data, etc.