API / JavaScript / Programmings / Technologies

Getting Started with IndexedDB

Overview

IndexedDB  is an API for storing significant amounts of structured data in user’s browser. It helps to do high performance  searches using indexes. The data stored in IndexedDB is persistent and work in online and offline.  It provides both a synchronous and an asynchronous API. In practice, however, all current implementations are asynchronous, and requests will not block the user interface from loading.

Like most web storage solutions, IndexedDB follows a same-origin-policy. So while you can access stored data within a domain, you cannot access data across different domains.

There  are some other traditional way to store data in browser, early broadly used one is cookies.

There are limitations and drawbacks, when using cookies, it limited to about 4 KB of data.Cookies are send along with every HTTP Request, it slows down your application by sending same data over and over needlessly.Most browsers allow only 20 cookies per site; if you try to store more, the oldest cookies are discarded.Because cookies have been used to spy on people’s surfing behavior, security-conscious people and companies turn them off or request to be asked every time whether a cookie should be set.

Another Broadly used option is Local Storage. localStorage, or more accurately DOM Storage, was designed for smaller amounts of data. It’s essentially a strings only key – value storage, with a simplistic synchronous API. We cannot store JavaScript objects directly into localStorage. We need to convert the objects into string to store. So direct querying is not possible in localStorage

Unlike cookies and DOM Storage, IndexedDB provides features that enable you to group, iterate, search, and filter JavaScript objects. IndexedDB is a superior solution for offline storage in browses when we handle the large amount of structured data. But compared to DOM Storage, its API is quite complicated. There are some polyfills and wrappers like localForage and dexie.js  to make it simple. localForage is a polyfill which use IndexedDB in background, has some fallback mechanism to WebSQL and then to localStorage in browsers when IndexedDB is not supported.

dexie.js is a wrapper for IndexedDB that allows much faster code development via simple syntax.

IndexedDB is a transactional database system, while it  is a JavaScript object-oriented database where data stores in the form of JavaScript objects. Objects are grouped into object stores, and these objects are indexed with a key. You can run basic  queries on your database and fetch records by looking up theirs keys in specific key ranges. And also we can store images and files in IndexedDB.

 

Getting Started with IndexedDB API

Here we are going to discuss indexed db operations with an example. The example is available in this GitHub.

i. Create Database and Object Store with Indexes

In the following example, we are going to create a database and employee object store which holds employee details by their “EmployeeID” attribute.  Additionaly “name” and “designation” attribute  make as indexes. “name” attribute indexed with unique constraints, so it does not allow same name repeating (case-sensitive). Indexes are used to lookup table.

A connection to the database is opened. If the “inapp” database did not already exist, it is created and an event handler creates the object store and indexes.

var request = indexedDB.open("inapp");
request.onupgradeneeded = function() {

// The database did not previously exist, so create object stores and indexes.

db = request.result;
var store = db.createObjectStore("employees", {keyPath: "empid"});
var nameIndex = store.createIndex("by_name", "name", {unique: true});
var designationIndex = store.createIndex("by_designation", "designation");

// Populate with initial data.

store.put({name: "Mohammed Safeer", designation: "Software Engineer", empid: "1"});
store.put({name: "Damodaran", designation: "System Analyst", empid: "2"});
store.put({name: "Ratheesh Kumar", designation: "Software Engineer", empid: "3"});

};

ii. Add data to Object Store

The following example populates the database using a transaction.

var tx = db.transaction("employees", "readwrite");
var store = tx.objectStore("employees");
var request = store.put({empid: "4", name: "John", designation: "Business Analyst"});
request.onsuccess = function(){
// data added successfully
}

request.onerror = function() {
// The uniqueness constraint of the "by_name" index failed.
console.log(request.error);
// Could call request.preventDefault() to prevent the transaction from aborting.
};

tx.onabort = function() {
// Otherwise the transaction will automatically abort due the failed request.
console.log(tx.error);
};

iii. Update data to Object Store

The following example update the entry with employee id 4 using a transaction. Update is same as Insert, here we use an existing Key Path value (here empid 4 in this example)

var tx = db.transaction("employees", "readwrite");
var store = tx.objectStore("employees");
var request = store.put({empid: "4", name: "James", designation: "Marketing Manager"});

iv. Search Object Store with index and cursor

The following example looks up all employee in the database by name using an index and a cursor. Note that it is case sensitive.

var tx = db.transaction("employees", "readonly"); 
var store = tx.objectStore("employees"); 
var index = store.index("by_name"); 
var request = index.openCursor(IDBKeyRange.only(“John”));   

request.onsuccess = function(e) { 
var cursor = e.target.result if (cursor) { 
// Called for each matching record. cursor.continue(); 
} else { 
// No more matching records. 
} 
};

v. Retrieve whole employees in Object Store

The following example lists all the employees in the employee objectstore

var tx = db.transaction("employees", "readonly");
var store = tx.objectStore("employees");
// Get everything in the store
var keyRange = IDBKeyRange.lowerBound(0);
var request = store.openCursor(keyRange);

// This fires once per row in the store. So, for simplicity,
// collect the data in an array (data), and pass it in the
// callback in one go.

var data = [];
request.onsuccess = function(e) {
var result = e.target.result;

// If there's data, add it to array
if (result) {
data.push(result.value);
result.continue();
// Reach the end of the data
} else {
callback(data);
}

};

vi. Delete An entry from Object Store with Key Path

In the following example, we deletes an entry with empid (Key Path) value 4

var tx = db.transaction("employees", "readwrite");
var store = tx.objectStore("employees");
var request = store.delete(“4”);
 
request.onsuccess = function() {
// do something
};

vii. Clear Object Store The following example clear object store “employees”

var tx = db.transaction("employees", "readwrite"); 
var store = tx.objectStore("employees"); 
store.clear();

This Example is available at https://github.com/safeer-in/IndexedDBTutorial.

This post is also published on https://inapp.com/indexeddb-a-web-api-for-client-side-storage/

Advertisements

One thought on “Getting Started with IndexedDB

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s