HTML 5 IndexedDB Database

Introduction


In my previous article, I discussed the Web SQL Database in HTML 5. This article explains the IndexedDB database, its features and the differences between Web SQL and IndexedDB.
 

About IndexedDB


This is new in the HTML 5 specification. It is not the same as a relational database. By using IndexedDB you can store a large number of objects locally. This is a new JavaScript API that is offered by HTML 5. The IndexedDB API is a specification for an indexed database that is present within our browser. As I said, it is not the same as a relational database so it does not have a table, rows, and columns like a relational database.
 
In a relational database, to store data we write a database query, like:
insert in <table_name>([column_1], [column_2]......[column_n]) values ([val_1],[val_2],.....,[val_n])

The same as for select, update and delete we have different queries that we also have used in a Web SQL Database. But as I said an IndexedDB store objects. So indexedDB has a different way to store and create objects. In this first you create an object to store a type of data; simply stated, we store JavaScript objects. The objects may have a simple value (like string, date and so on) or hierarchical objects (like JavaScript object or arrays). Each object consists of a key with its corresponding value and each object stores a collection of indexes that make it efficient to query and iteration can be fast across objects. In an IndexedDB the query is replaced by an index and the IndexedDB produces a cursor to be used to iterate across the result set.
 
The IndexedDB API is exposed through the window.indexedDB object. When you work on an IndexedDB, the following lines of code you should always use, to determine whether or not the browser supports IndexedDB:
  1. if (!window.indexedDB) {    
  2.     window.alert("Your browser doesn't support IndexedDB. ");    
  3. }  
For checking in various  browsers you can also use this:
  1. var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB;    
  2.     
  3. if(!indexedDB){    
  4. alert("Your browser doesn't support IndexedDB ");    
  5. }   

    Creating and Opening IndexedDB Database

     
    If we want to work on any database then the first step is to create a database then make a connection object to open the database.
    Before creating the database I want to tell you about the two API modes of IndexedDB.
    1. Synchronous mode: This mode was created to be used only in conjunction with web workers. But most browsers currently do not support the synchronous mode.

    2. Asynchronous mode: Using this mode we get the benefits of having non-blocking operations, so if you have a large amount of data to store and you are on a low-power device with not much memory and I/O then you will never like that your web application has crashed while storing data. This is not a new concept in web applications but is a very nice concept.
    Now how to create and open the IndexedDB database: By an asynchronous call of the open function of the IndexedDB API, you can create an object for the database. If the database does not exist then it will first be created then the object for that database will be created.
     
    Syntax
    1. var dbOpenRequest = indexedDB.open([Database_Name],[Version]);  
    The Open function has the following 2 parameters: 
    • Database Name: This parameter is used as the name of the database that you want to open. This is a required parameter. Its data type is a string. 
    • Version: This parameter specifies the version of the database. This parameter is an optional parameter. Its data type is an unsigned long number.
    The Open function returns an IDBRequest object that fires events to indicate the result of the request. This is an object that you can use to fire onsuccess and onerror events.
     
    Example

    The following example describes how to create a database or its object.
    1. <!DOCTYPE html>    
    2. <html>    
    3.     <body>    
    4.         <script>    
    5.             var Database_Name = "MyDatabase";    
    6.             var dbObj;    
    7.             var request = indexedDB.open(Database_Name)    
    8.             request.onsuccess = function (e) {    
    9.                 document.getElementById("result").innerHTML = "Database Opened :)";    
    10.                 dbObj = request.result;    
    11.             }    
    12.             request.onerror = function (e) {    
    13.                 console.log("Error:" + e.target.errorCode)    
    14.                 document.getElementById("result").innerHTML = "Error! The Database connection not opened. Please See The Log";    
    15.             }    
    16.         </script>    
    17.         <P id="result"></P>    
    18.     </body>    
    19. </html>    
      Output

      When this code is run in a browser then
       
       
      If you want to see whether or not the database is created then open the developer's tool and the output will look like this (in Chrome)
       
       
       

      Creating an Object Store in IndexedDB


      The IndexedDB can hold one or more than one objectStores. objectStores again resemble a table in a relational database but not the same as a relational database, it is very different. They have key/value records and can have key paths, key generators, and indexes. By using the createObjectStore function you can create an objectStore. The function createObjectStore takes the following parameters:
      • Name: The name of the object store to be created. Its data type is DOMString.
      • Optional Parameters: This optional parameter can hold any type of value. This parameter can have one or both of the following attributes:

        1. keyPath: A DOMString value specifying the keypath for the object-store.
        2. autoIncrement: A boolean value indicates whether the key-value automatically increases as a record is added to the object-store.
      Object stores also have indexes that will be used later when we retrieve data from the IndexedDB. By using the CreateIndex function you can create indexes in the object-store. The createIndex takes the following parameters:
      • Name: Name of the index. Its datatype is a string.
      • KeyPath: Name of the field to be indexed. Its datatype can be any.
      • Optional Parameters: Its type is an object. The optional parameters can have one or both of the following attributes:

        1. Unique: Its type is Boolean and decides whether the index allows duplicate values. If the attribute value is true then a duplicate value is not allowed. If the attribute value is false then duplicate values are allowed. By default It's value is false.

        2. multiEntry: A Boolean value that determines the results when multiple rows in the object match individual key values. The resulting object is an array when it happens. If its value is true then the resulting array can contain only a single item; the key of the item contains an array of the matching values. When this parameter is false (the default), the result array contains one item for each item that matches the key value. (According to the MSDN.)
      Note: Multi-entry indexes are not supported by a Windows Store app.
       
      Example
      1. <!DOCTYPE html>    
      2. <html>    
      3.     <body>    
      4.         <script>    
      5.             //Data which we want to store inside the database.    
      6.             var friends_Data = [    
      7.             { Name: "Sourabh Somani", Email: "sourabh_somani2010@hotmail.com", Location: "Chittorgarh" },    
      8.             { Name: "Shaili Dashora", Email: "shailidashora@hotmail.com", Location: "Chittorgarh" },    
      9.             { Name: "Divya Sharma", Email: "divyasharma@hotmail.com", Location: "Chittorgarh" },    
      10.             { Name: "Mahesh Chand", Email: "maheshchand@gmail.com", Location: "Philadelphia, Pennsylvania" },    
      11.             { Name: "Dinesh Beniwal", Email: "dinesh@gmail.com", Location: "Delhi" }    
      12.             ];    
      13.     
      14.             function initDB() {    
      15.                 var Database_Name = "FriendsDB";    
      16.                 var DB_Version="1";    
      17.                 var dbObj;    
      18.                 var request = indexedDB.open(Database_Name,DB_Version)    
      19.                 request.onsuccess = function (e) {    
      20.                     document.getElementById("result").innerHTML = "Database Opened :)";    
      21.                     dbObj = request.result;    
      22.                 }    
      23.                 request.onerror = function (e) {    
      24.                     console.log("Error:" + e.target.errorCode)    
      25.                     document.getElementById("result").innerHTML = "Error! The Database connection not opened. Please See The Log";    
      26.                 }    
      27.                 //the onupgradeneeded event is fire when a database is opened with a new version number    
      28.                 request.onupgradeneeded = function (e) {    
      29.                     //creating Object Store    
      30.                     var objectStore = e.currentTarget.result.createObjectStore("MyObjectStore", { keyPath: "id", autoIncrement: true });    
      31.     
      32.                     //creating Indexes    
      33.                     objectStore.createIndex("Name", "Name", { unique: false });    
      34.                     objectStore.createIndex("Email", "Email", { unique: true });    
      35.                     objectStore.createIndex("Location", "Location", { unique: false });    
      36.     
      37.                     //To store the Data    
      38.                     for (i in friends_Data) {    
      39.                         objectStore.add(friends_Data[i]);    
      40.                     }    
      41.                 };    
      42.             }    
      43.         </script>    
      44.         <button id="btnCreateStore" onclick="initDB()">Create Store</button>    
      45.         <P id="result"></P>    
      46.     </body>    
      47. </html>  
      Output
      1. Initially when the page is loaded

         
      2. After clicking on the Create Store Button


        If you want to see whether or not the data was stored then open the developer's tool then (in Chrome) go to the resource and then open the IndexedDB tab.

        My stored output is as follows:





      Transaction in IndexedDB


      If you have an object store and you want to perform CRUD(Create/Read/Update/Delete) operations, there is only one way to perform CRUD operations in IndexedDB, by using a transaction object (IDBTransaction).
       
      The IDBTransation object represents a group of operations made against a database. The IDBTransaction object can be created in 3 different modes:
      1. read-only: This is the default mode. This mode does not allow changes. 
      2. read/write: This mode allows changes.
      3. version change: Objects in the database can be created using this mode.
      Note: You should use read/write mode only when you are doing an update operation, in other cases always use read-only mode. Because read-only transactions can run concurrently. 
       
      The transactions are asynchronous so you can wire a transaction to abort, error, and Complete events.
       
      Using the transaction function you can begin your transaction. The transaction function takes the following 2 parameters:
      • Name: Name of the object-store. Its datatype can be a string to specify a single value or can be a string array to specify multiple values.
      • mode: This is an optional parameter. All the modes are discussed above.
      Example
      1. var transaction = db.transaction("MyObjectStore", IDBTransaction.READ_WRITE);    
      2. var objectStore = transaction.objectStore("MyObjectStore");                        
      3. var request = objectStore.add({ Name: Name, Email: Email, Location:Location});    
      4. request.onsuccess = function (e) {    
      5.     // do something when the add succeeded                              
      6. };    
      7. transaction.oncomplete = function(e) {      
      8.   // do something after the transaction completed      
      9. };    
      10. transaction.onabortfunction(e) {      
      11.   // do something after the transaction aborted     
      12. };    
      13. transaction.onerrortfunction(e) {      
      14.   // do something after the transaction canceled    
      15. };   

      Retrieving Data from the IndexedDB

       
      Using the get method you can retrieve the records from the object-store. The get method accepts the keys to retrieve data.
       
      Example
      1. <!DOCTYPE html>    
      2. <html>    
      3.     <body>    
      4.         <script>    
      5.             var Database_Name = "FriendsDB";    
      6.             var DB_Version = "1";    
      7.             var dbObj;    
      8.             var request = indexedDB.open(Database_Name, DB_Version)    
      9.     
      10.             request.onsuccess = function (e) {    
      11.                 dbObj = request.result;    
      12.                 var transaction = dbObj.transaction("MyObjectStore");    
      13.                 var objectStore = transaction.objectStore("MyObjectStore");    
      14.                 var req = objectStore.get(1);    
      15.                 req.onsuccess = function (e) {    
      16.                     document.getElementById("result").innerHTML = "Name for id 1 " + req.result.Name + "<br/>Email: " + req.result.Email + "</br>Location: " + req.result.Location;    
      17.                 };    
      18.             }    
      19.             request.onerror = function (e) {    
      20.                 console.log("Error:" + e.target.errorCode)    
      21.                 document.getElementById("result").innerHTML = "Error! The Database connection not opened. Please See The Log";    
      22.             }    
      23.         </script>    
      24.         <P id="result"></P>    
      25.     </body>    
      26. </html>    
      Output


      Difference Between WebSQL and IndexedDB

       
      WebSQL
      IndexedDB
      Relational database implementation on the client-side
      Not Like a Relational database and stores objects
      No Indexing happens
      Indexing of the objects
      Searching and read-write operations are slow compared to IndexedDB
      Searching is fast because indexing happens. And read and write operations can be fast
      Cannot store JavaScript objects
      Overhead of SQL language you need to master and transform your JavaScript objects into a relational schema
      Can store JavaScript objects and indexing them based on application needs
      Cannot work in asynchronous mode
      Works in asynchronous mode with moderately granular locking per transaction. This allows you to work inside the event-driven module of JavaScript.
      Not object-driven
      Object driven
      Data is stored in the table and table contains rows and columns
      Objects are stored in objectStore that contains objects and keys
      A query mechanism is SQL
      Cursor APIs, Key Range APIs, and Application Code are the mechanism to query the objects
      Lock can happen on databases, tables, or rows on READ_WRITE transactions
      Lock can happen on database VERSION_CHANGE transaction, on an objectStore READ_ONLY and READ_WRITE transactions
      Transaction creation is explicit. The default is to rollback unless we call commit.
      Transaction creation is explicit. The default is to commit unless we call abort or there is an error that is not caught.


      Conclusion

       
      In this article, we studied IndexedDB database, its features and the differences between Web SQL and IndexedDB.