Introduction
In my previous article I discussed
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 stores 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:
- if (!window.indexedDB) {
- window.alert("Your browser doesn't support IndexedDB. ");
- }
For checking in various browsers you can also use this:
- var indexedDB = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB;
-
- if(!indexedDB){
- alert("Your browser doesn't support IndexedDB ");
- }
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.
- Synchronous mode: This mode was created to be used only with conjunction with web workers. But most browsers curently do not support the synchronous mode.
- 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
- var dbOpenRequest = indexedDB.open([Database_Name],[Version]);
The Open function has the following 2 parameters:
- Database Name: This parameter is used as a name of the database that you want to open. This is a required parameter. It's data type is string.
- Version: This parameter specifies the version of the database. This parameter is an optional parameter. It's data type is 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.
- <!DOCTYPE html>
- <html>
- <body>
- <script>
- var Database_Name = "MyDatabase";
- var dbObj;
- var request = indexedDB.open(Database_Name)
- request.onsuccess = function (e) {
- document.getElementById("result").innerHTML = "Database Opened :)";
- dbObj = request.result;
- }
- request.onerror = function (e) {
- console.log("Error:" + e.target.errorCode)
- document.getElementById("result").innerHTML = "Error! The Database connection not opened. Please See The Log";
- }
- </script>
- <P id="result"></P>
- </body>
- </html>
OutputWhen this code is run in a browser then:
If you want to see whether or not the database is created then open the developers 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. It's 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 weather 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. It's datatype is string.
- KeyPath: Name of the field to be indexed. It's datatype can be any.
- Optional Parameters: It's type is object. The optional parameters can have one or both of the following attributes:
1. Unique: It's 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
- <!DOCTYPE html>
- <html>
- <body>
- <script>
-
- var friends_Data = [
- { Name: "Sourabh Somani", Email: "[email protected]", Location: "Chittorgarh" },
- { Name: "Shaili Dashora", Email: "[email protected]", Location: "Chittorgarh" },
- { Name: "Divya Sharma", Email: "[email protected]", Location: "Chittorgarh" },
- { Name: "Mahesh Chand", Email: "[email protected]", Location: "Philadelphia, Pennsylvania" },
- { Name: "Dinesh Beniwal", Email: "[email protected]", Location: "Delhi" }
- ];
-
- function initDB() {
- var Database_Name = "FriendsDB";
- var DB_Version="1";
- var dbObj;
- var request = indexedDB.open(Database_Name,DB_Version)
- request.onsuccess = function (e) {
- document.getElementById("result").innerHTML = "Database Opened :)";
- dbObj = request.result;
- }
- request.onerror = function (e) {
- console.log("Error:" + e.target.errorCode)
- document.getElementById("result").innerHTML = "Error! The Database connection not opened. Please See The Log";
- }
-
- request.onupgradeneeded = function (e) {
-
- var objectStore = e.currentTarget.result.createObjectStore("MyObjectStore", { keyPath: "id", autoIncrement: true });
-
-
- objectStore.createIndex("Name", "Name", { unique: false });
- objectStore.createIndex("Email", "Email", { unique: true });
- objectStore.createIndex("Location", "Location", { unique: false });
-
-
- for (i in friends_Data) {
- objectStore.add(friends_Data[i]);
- }
- };
- }
- </script>
- <button id="btnCreateStore" onclick="initDB()">Create Store</button>
- <P id="result"></P>
- </body>
- </html>
Output
- Initially when the page is loaded
- After clicking on the Create Store Button
If you want to see whether or not the data was stored then open the developers 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:
- read-only: This is the default mode. This mode does not allow changes.
- read/write: This mode allows changes.
- 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
- var transaction = db.transaction("MyObjectStore", IDBTransaction.READ_WRITE);
- var objectStore = transaction.objectStore("MyObjectStore");
- var request = objectStore.add({ Name: Name, Email: Email, Location:Location});
- request.onsuccess = function (e) {
-
- };
- transaction.oncomplete = function(e) {
-
- };
- transaction.onabort= function(e) {
-
- };
- transaction.onerrort= function(e) {
-
- };
Retrieving Data from the IndexedDB
Using the get method you can retrieve the records from the object store. The get method accepts keys to retrieve data.
Example
- <!DOCTYPE html>
- <html>
- <body>
- <script>
- var Database_Name = "FriendsDB";
- var DB_Version = "1";
- var dbObj;
- var request = indexedDB.open(Database_Name, DB_Version)
-
- request.onsuccess = function (e) {
- dbObj = request.result;
- var transaction = dbObj.transaction("MyObjectStore");
- var objectStore = transaction.objectStore("MyObjectStore");
- var req = objectStore.get(1);
- req.onsuccess = function (e) {
- document.getElementById("result").innerHTML = "Name for id 1 " + req.result.Name + "<br/>Email: " + req.result.Email + "</br>Location: " + req.result.Location;
- };
- }
- request.onerror = function (e) {
- console.log("Error:" + e.target.errorCode)
- document.getElementById("result").innerHTML = "Error! The Database connection not opened. Please See The Log";
- }
- </script>
- <P id="result"></P>
- </body>
- </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 |
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. |