Learn how to use IndexedDB


IndexedDB getAll() Methods Sample Searching in IndexedDB Multiple keys query in IndexedDB (sql OR)


IndexedDB is an API for storing data in user's browser. One can also use cookies and local storage but they don't provide database like usability the way IndexedDB do. The data stored in IndexedDB is persistence. It provides rich query abilities and is available both in online and offline mode. It can be used to store large amount of data. >Note: IndexedDB is currently a Candidate Recommendation and is only available in modern desktop web browsers. IndexedDB stores data in form of objects along with an index key. Everything that happens in IndexedDB happens through transactions. The objects are grouped into object stores. The IndexedDB contains object stores and these object stores contain objects along with a unique keyPath.

IndexedDB vs LocalStorage, Cookies

Although both were developed to provide client side data storage but both have different approaches and should be chosen according to the needs. localStorage stores data in key-value pair but unlike IndexedDB, they are not stored in form of objects. Instead, it stores only string key-value pairs. A simple trick to store objects in localstorage is to use JSON.stringify(), similarly to store it back to object form after reading you will need to do JSON.parse(). // our array var movies = ["Reservoir Dogs", "Pulp Fiction", "Jackie Brown", "Kill Bill", "Death Proof", "Inglourious Basterds"]; // storing our array as a string localStorage.setItem("thisfilename", JSON.stringify(movies)); // retrieving our data and converting it back into an array var retrievedData = localStorage.getItem("thisfilename"); var movies2 = JSON.parse(retrievedData); //making sure it still is an array alert(movies2.length); But it will not be a good solution when storing large number of complex objects. Moreover, localstorage was designed for smaller data and provides synchronous API. IndexedDB is great for handling large amount of data and comes with asynchronous API. It uses indexes to store data and transactions to perform operations. It even supports simple data types. IndexedDB may seem better than localstorage,but its API is complex to use and currently only latest desktop browsers are supported. For basic storage you may continue to use local storage but if you are going to store large amount of data, IndexedDB will be a better suited option as it will also allow you to perform complex search queries.

IndexedDB vs Web SQL

Beware. This specification is no longer in active maintenance and the Web Applications Working Group does not intend to maintain it further.

IndexedDB vs Cookies

Cookies may sound tasty but they are not. Cookies are sent and received with every http request resulting in additional traffic. e.g. if you have 10KB of cookies and made 10 request, then total 100KB of data will be transferred. Also, cookies are only strings and hence need to be parsed. Also, the space of storing cookies is limited and many users block their cookies. Hence cookies can be only good for storing very small non-crucial data.

How to use IndexedDB

To understand IndexedDB, I have created a basic web app that stores the roll numbers and names of students in IndexedDB. It provides basic add, remove, access and update option. https://github.com/SuyashMShepHertz/indexedDB_sample

Opening a Database

Firstly you need to make sure, that your browser supports IndexedDB. As mentioned earlier, it is still a candidate recommendation and hence not supported in all browsers. indexedDB = indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; if(!indexedDB) { console.log("Your Browser does not support IndexedDB"); } Once, we know IndexedDB is supported, we have to open a database. You can not simply open a database, rather IndexedDB requires you to create a request to open a database. var request = indexedDB.open("testDB", 2); here first parameter is the name of database and second parameter is version of database. The version allows you to represent your DB's current schema i.e the object stores stored in it and their structures. If you upgrade your database you will only need to create/delete few object stores rather than creating/deleting all the object stores. When you will increase the version of your database, onupgradeneeded event will be triggered. Along with onupgradeneeded, there are success, error and blocked events. var db; request.onerror = function(event){ console.log("Error opening DB", event); } request.onupgradeneeded = function(event){ console.log("Upgrading"); db = event.target.result; var objectStore = db.createObjectStore("students", { keyPath : "rollNo" }); }; request.onsuccess = function(event){ console.log("Success opening DB"); db = event.target.result; } onupgradeneeded event will be called whenever the webpage is hit for the first time on user's web browser or if there is an upgrade in version of database. Hence, you will have to create your object stores only in onupgradeneeded event. If there is no upgrade in version and the page has been opened previously, you will get onsuccess event. onerror event occurs if there is some error. onblocked event occurs if previous connection was never closed. In above code snippet, we are creating a Object Store named “students” with index key “roll no”.

Adding Object to ObjectStore

To add data in our DB, we first need to create a transaction with read write permission on our object store. To perform any action on object store we need to create a transaction. Following it, access our object store and add the data to it. var transaction = db.transaction(["students"],"readwrite"); transaction.oncomplete = function(event) { console.log("Success"); }; transaction.onerror = function(event) { console.log("Error"); }; var objectStore = transaction.objectStore("students"); objectStore.add({rollNo: rollNo, name: name}); Removing Object from ObjectStore Deletion is similar to addition, you need to create transaction and call delete function with the key of the object to be removed. db.transaction(["students"],"readwrite").objectStore("students").delete(rollNo); I have mixed up statements to make it more easier but they perform the same.

Accessing an object with the key

Use the get() function passing the key of the object to be retrieved. var request = db.transaction(["students"],"readwrite").objectStore("students").get(rollNo); request.onsuccess = function(event){ console.log("Name : "+request.result.name); }; Updating an Object To update an object, first get that object and then after making changes put back it to object store. var transaction = db.transaction(["students"],"readwrite"); var objectStore = transaction.objectStore("students"); var request = objectStore.get(rollNo); request.onsuccess = function(event){ console.log("Updating : "+request.result.name + " to " + name); request.result.name = name;< objectStore.put(request.result); }; The full source code of above sample web page is here. If you have any questions or need any further assistance, please feel free to write us at support@shephertz.com. Please check out the demo before we start the tutorial. a href="http://www.onlywebpro.com/demo/jquery/indexeddb.html" target="_blank" class="demo_btn">View Demo

Get Started Example

Since we know that the IndexedDB API is still evolve, so we need to include the following prefixes of implementation. Besides, for best practice, we should always provide fallback content for unsupported browsers. //prefixes of implementation that we want to test indexedDB = indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; //prefixes of window.IDB objects window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction; window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange if (!indexedDB) { window.alert("Your browser doesn't support a stable version of IndexedDB.") }

Opening an IndexedDB Database

Before we create the database, the very first thing to do is to prepare some data for the database. Let say we have some customer information as shown below: const customerData = [ { id: "00-01", name: "Bill", age: 35, email: "bill@company.com" }, { id: "00-02", name: "Donna", age: 32, email: "donna@home.org" } ]; 2 data enetries, each entry consists of the information of ID, name, age and email of the customer. Before we can insert the data into the database, we need to open our database using the open() method as shown below: var db; var request = indexedDB.open("newDatabase", 1); request.onerror = function(event) { console.log("error: "); }; request.onsuccess = function(event) { db = request.result; console.log("success: "+ db); }; request.onupgradeneeded = function(event) {} As you can see we have opened a database with the name “newDatabase” and the version of the database. All IndexedDB databases are stored in the same origin with the web application / website. Example, if myblog.com might has a database named “newDatabase” and mybusiness.com also might has a totally distinct database named “newDatabase”. The open() method has accepts 2 parameters, the first is the name ofthe database. It will checks whether the database named “newDatabase” is already exist or not, if it is exist, then it will open the database, else it will create a new one. The second paramter of open() method is the version of the database, which allows you to update the schema of the database.

Onsuccess handler

If everything succeeds, then a success event “onsuccess” is fired with request as its target and we have save the request’s result for later use by assigning it to db variable.

Onerror handler

If the process of opening database fail, then an error event “onerror” is fired.

Onupgradeneeded handler

If you want to update the database, or to create, delete or modify the database, then you have to implement the onupgradeneeded handler or which will be called as part of a versionchange transaction that allows you to make any changes on the database. Please bear in mind that, the “onupgradeneeded” handler is the only place for you to alter the structure of database.

Structuring the Database

Again, IndexedDB is NOT same as a Relational Database. IndexedDB uses object stores to store data rather than tables. Whenever a value is stored in an object store, it is associated with a key. The interesting of IndexedDB is it allows us to create indices on any object store. An index lets us to access the values stored in object store using the value of a property of the stored object. This may sound confusing now, but you may know it better after go through the entire lesson. The following code illustrates how we create the object store and insert the pre-prepared data into it: request.onupgradeneeded = function(event) { var db = event.target.result; var objectStore = db.createObjectStore("customers", {keyPath: "id"}); for (var i in customerData) { objectStore.add(customerData[i]); } } We create an object store using createObjectStore() method. This method accepts 2 parameters: – name of the store and a parameter object. In this case, we have named the object store as “customers” and defined a keyPath that is the property that makes an individual object in the store unique. In this example, we have use the “id” as keyPath, which is unique value in the object store, and you must make sure that the “id” property must be present in every objects in the object store. Once the object store is created, we can start adding the data into it using for loop.

Manually Adding Data

You may probably want to manually add extra data into the database, then here is how you should write the function: function add() { var request = db.transaction(["customers"], "readwrite") .objectStore("customers") .add({ id: "00-03", name: "Kenny", age: 19, email: "kenny@planet.org" }); request.onsuccess = function(event) { alert("Kenny has been added to your database."); }; request.onerror = function(event) { alert("Unable to add data\r\nKenny is aready exist in your database! "); } } We have just manually added a new data named with “Kenny” to the object store “customer” using add() method. Before we can do anything (read, write, modify) to our database, we have to start use a transaction. The transaction() method is used to specify which object stores you want the transaction to span. The transaction() mthod accepts 3 parameters (second and third are optional): – First is the list of object store you want to deal with, second is whether you want to read only or read and write to the object, third is the versionchange. The transaction method let you have the object store that you specified and insert, modify or delete the data that you need. In this case, we insert the data using add() method.

Retrieving Data

Let’s retrieve the data from the database. We can retrieve the data using get() method. function read() { var transaction = db.transaction(["customers"]); var objectStore = transaction.objectStore("customers"); var request = objectStore.get("00-03"); request.onerror = function(event) { alert("Unable to retrieve daa from database!"); }; request.onsuccess = function(event) { // Do something with the request.result! if(request.result) { alert("Name: " + request.result.name + ", Age: " + request.result.age + ", Email: " + request.result.email); } else { alert("Kenny couldn't be found in your database!"); } }; } We use get() method to retrieve the data we need from object store. Since we already set the id of object as keyPath earlier, so the get() method will look up the object that has the same id value. This will return us the object named “Kenny”which is the object that we manually added in the previous function.

Retrieving All Data

If you want get all data instead of one from object store, then you may need to use a cursor. Here is another function that using cursor to retrieve all data from object store: function readAll() { var objectStore = db.transaction("customers").objectStore("customers"); objectStore.openCursor().onsuccess = function(event) { var cursor = event.target.result; if (cursor) { alert("Name for id " + cursor.key + " is " + cursor.value.name + ", Age: " + cursor.value.age + ", Email: " + cursor.value.email); cursor.continue(); } else { alert("No more entries!"); } }; } As you can see, we implement the openCursor() method to accomplish the goal. The openCursor() is used to iterate over multiple records in a database. It can accepts several parameters, such as limit the range items, the direction that we want to iterate and etc. In this case, we leave it no parameters. The cursor object itself is the result of the request. We have implement the continue() function to continues with the next iteration in the loop. When the loop reached end, then we will get the alert with content “No more entries!”.

Removing Data

Removing data from object store is very similar to other functions that we have just learnt. Here is how the code looks like: function remove() { var request = db.transaction(["customers"], "readwrite") .objectStore("customers") .delete("00-03"); request.onsuccess = function(event) { alert("Kenny's entry has been removed from your database."); }; } If you want to remove data from object store, then you may need to use delete() method. You have to pass the keyPath of the object that you want to remove as paramter to the delete() method. In this case, we remove the object with named “Kenny” which we added via add function just now.

The HTML

We have just wrote all the functions, and now is the time to display the data using the onclick event that binded to HTML button. <!DOCTYPE html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>IndexedDb Demo | onlyWebPro.com</title> </head> <body> <button onclick="read()">Read single data from indexedDb</button> <button onclick="readAll()">Read all data from indexedDb</button> <button onclick="add()">Add data to indexedDb</button> <button onclick="remove()">Delete data from indexedDb</button> </body> </html> We have prepared 4 HTML buttons. Each of the button is used to trigger the Javascript function that we wrote earlier in this article. Save your document and view it in supported browser. Have fun! 🙂

The Final Code

<!DOCTYPE html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>IndexedDb Demo | onlyWebPro.com</title> <script type="text/javascript"> //prefixes of implementation that we want to test indexedDB = indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; //prefixes of window.IDB objects window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction; window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange if (!indexedDB) { window.alert("Your browser doesn't support a stable version of IndexedDB.") } const customerData = [ { id: "00-01", name: "Bill", age: 35, email: "bill@company.com" }, { id: "00-02", name: "Donna", age: 32, email: "donna@home.org" } ]; var db; var request = indexedDB.open("newDatabase", 1); request.onerror = function(event) { console.log("error: "); }; request.onsuccess = function(event) { db = request.result; console.log("success: "+ db); }; request.onupgradeneeded = function(event) { var db = event.target.result; var objectStore = db.createObjectStore("customers", {keyPath: "id"}); for (var i in customerData) { objectStore.add(customerData[i]); } } function read() { var transaction = db.transaction(["customers"]); var objectStore = transaction.objectStore("customers"); var request = objectStore.get("00-03"); request.onerror = function(event) { alert("Unable to retrieve daa from database!"); }; request.onsuccess = function(event) { // Do something with the request.result! if(request.result) { alert("Name: " + request.result.name + ", Age: " + request.result.age + ", Email: " + request.result.email); } else { alert("Kenny couldn't be found in your database!"); } }; } function readAll() { var objectStore = db.transaction("customers").objectStore("customers"); objectStore.openCursor().onsuccess = function(event) { var cursor = event.target.result; if (cursor) { alert("Name for id " + cursor.key + " is " + cursor.value.name + ", Age: " + cursor.value.age + ", Email: " + cursor.value.email); cursor.continue(); } else { alert("No more entries!"); } }; } function add() { var request = db.transaction(["customers"], "readwrite") .objectStore("customers") .add({ id: "00-03", name: "Kenny", age: 19, email: "kenny@planet.org" }); request.onsuccess = function(event) { alert("Kenny has been added to your database."); }; request.onerror = function(event) { alert("Unable to add data\r\nKenny aready exist! "); } } function remove() { var request = db.transaction(["customers"], "readwrite") .objectStore("customers").delete("00-03"); request.onsuccess = function(event) { alert("Kenny's entry has been removed from your database."); }; } </script> </head> <body> <button onclick="read()">Read single data from indexedDb</button> <button onclick="readAll()">Read all data from indexedDb</button> <button onclick="add()">Add data to indexedDb</button> <button onclick="remove()">Delete data from indexedDb</button> </body> </html> a href="http://www.onlywebpro.com/demo/jquery/indexeddb.html" target="_blank" class="demo_btn">View Demo

Conclusion

The HTML5 IndexedDB API is very useful and powerful. You can leverage it to create rich, online and offline HTML5 application. In addition, with IndexedDB API, you can cache data to make traditional web applications especially mobile web applications load faster and more responsive without need to retrieve data from the web server each time. Create Your Own To-Do App with HTML5 and IndexedDB

IndexedDB Introduction

We are using Jake Archibald's IndexedDB Promised library, which is very similar to the IndexedDB API, but uses promises rather than events. This simplifies the API while maintaining its structure, so anything you learn using this library can be applied to the IndexedDB API directly.

Checking for IndexedDB support

Because IndexedDB isn't supported by all browsers, we need to check that the user's browser supports it before using it. The easiest way is to check the window object: if (!('indexedDB' in window)) { console.log('This browser doesn\'t support IndexedDB'); return; } We simply place this function at the beginning of our scripts and we're ready to use IndexedDB.

Opening a database

With IndexedDB you can create multiple databases with any names you choose. In general, there is just one database per app. To open a database, we use: idb.open(name, version, upgradeCallback) This method returns a promise that resolves to a database object. When using idb.open, you provide a name, version number, and an optional callback to set up the database. Here is an example of idb.open in context: (function() { 'use strict'; //check for support if (!('indexedDB' in window)) { console.log('This browser doesn\'t support IndexedDB'); return; } var dbPromise = idb.open('test-db1', 1); })(); We place our check for IndexedDB support at the top of the anonymous function. This exits out of the function if the browser doesn't support IndexedDB. We call idb.open to open a database named "test-db1". We have left out the optional callback function in this first example to keep things simple.

Working with object stores

. - Creating object stores

A database typically contains one or more object stores. Object stores can be thought of as similar to tables in SQL databases and should contain objects of the same "type" (not JavaScript data type). For example, for a site persisting user profiles and notes, we can imagine a "people" object store containing "person" objects, and a "notes" object store. A well structured IndexedDB database should have one object store for each type of data you need to persist. To ensure database integrity, object stores can only be created and removed in the callback function in idb.open. The callback receives an instance of UpgradeDB, a special object in the IDB Promised library that is used to create object stores. Call the createObjectStore method on UpgradeDB to create the object store: upgradeDb.createObjectStore('storeName', options); This method takes the name of the object store as well as a parameter object that lets us define various configuration properties for the object store. Below is an example of the createObjectStore method: (function() { 'use strict'; //check for support if (!('indexedDB' in window)) { console.log('This browser doesn\'t support IndexedDB'); return; } var dbPromise = idb.open('test-db2', 1, function(upgradeDb) { console.log('making a new object store'); if (!upgradeDb.objectStoreNames.contains('firstOS')) { upgradeDb.createObjectStore('firstOS'); } }); })(); Again, we first check the browser for IndexedDB support. This time we include the callback function in idb.open in order to create the object store. The browser throws an error if we try to create an object store that already exists in the database so we wrap the createObjectStore method in an if statement that checks if the object store exists. Inside the if block we call createObjectStore on the UpgradeDB object to create an object store named "firstOS".

. - Defining primary keys

When you define object stores, you can define how data is uniquely identified in the store using the primary key. You can define a primary key by either defining a key path, or by using a key generator. A key path is a property that always exists and contains a unique value. For example, in the case of a "people" object store we could choose the email address as the key path. upgradeDb.createObjectStore('people', {keyPath: 'email'}); This example creates an object store called "people" and assigns the "email" property as the primary key. You could also use a key generator, such as autoIncrement. The key generator creates a unique value for every object added to the object store. By default, if we don't specify a key, IndexedDB creates a key and stores it separately from the data. upgradeDb.createObjectStore('notes', {autoIncrement:true}); This example creates an object store called "notes" and sets the primary key to be assigned automatically as an auto incrementing number. upgradeDb.createObjectStore('logs', {keyPath: 'id', autoIncrement:true}); This example is similar to the previous example, but this time the auto incrementing value is assigned to a property called "id". Choosing which method to use to define the key depends on your data. If your data has a property that is always unique, you can make it the keypath to enforce this uniqueness. Otherwise, using an auto incrementing value makes sense. Let's look at an example: function() { 'use strict'; //check for support if (!('indexedDB' in window)) { console.log('This browser doesn\'t support IndexedDB'); return; } var dbPromise = idb.open('test-db3', 1, function(upgradeDb) { if (!upgradeDb.objectStoreNames.contains('people')) { upgradeDb.createObjectStore('people', {keyPath: 'email'}); } if (!upgradeDb.objectStoreNames.contains('notes')) { upgradeDb.createObjectStore('notes', {autoIncrement: true}); } if (!upgradeDb.objectStoreNames.contains('logs')) { upgradeDb.createObjectStore('logs', {keyPath: 'id', autoIncrement: true}); } }); })(); This code creates three object stores demonstrating the various ways of defining primary keys in object stores.

. - Defining indexes

Indexes are a kind of object store used to retrieve data from the reference object store by a specified property. An index lives inside the reference object store and contains the same data, but uses the specified property as its key path instead of the reference store's primary key. Indexes must be made when you create your object stores and can also be used to define a unique constraint on your data. To create an index, call the createIndex method on an object store instance: objectStore.createIndex('indexName', 'property', options); This method creates and returns an index object. createIndex takes the name of the new index as the first argument, and the second argument refers to the property on the data you want to index. The final argument lets you define two options that determine how the index operates: unique and multiEntry . If unique is set to true, the index does not allow duplicate values for a single key. multiEntry determines how createIndex behaves when the indexed property is an array. If it's set to true, createIndex adds an entry in the index for each array element. Otherwise, it adds a single entry containing the array. Here is an example: (function() { 'use strict'; //check for support if (!('indexedDB' in window)) { console.log('This browser doesn\'t support IndexedDB'); return; } var dbPromise = idb.open('test-db4', 1, function(upgradeDb) { if (!upgradeDb.objectStoreNames.contains('people')) { var peopleOS = upgradeDb.createObjectStore('people', {keyPath: 'email'}); peopleOS.createIndex('gender', 'gender', {unique: false}); peopleOS.createIndex('ssn', 'ssn', {unique: true}); } if (!upgradeDb.objectStoreNames.contains('notes')) { var notesOS = upgradeDb.createObjectStore('notes', {autoIncrement: true}); notesOS.createIndex('title', 'title', {unique: false}); } if (!upgradeDb.objectStoreNames.contains('logs')) { var logsOS = upgradeDb.createObjectStore('logs', {keyPath: 'id', autoIncrement: true}); } }); })(); In this example, the "people" and "notes" object stores have indexes. To create the indexes, we first assign the result of createObjectStore (which is an object store object) to a variable so we can call createIndex on it.

Working with data

In this section, we describe how to create, read, update, and delete data. These operations are all asynchronous, using promises where the IndexedDB API uses requests. This simplifies the API. Instead of listening for events triggered by the request, we can simply call .then on the database object returned from idb.open to start interactions with the database. All data operations in IndexedDB are carried out inside a transaction. Each operation has this form: Get database object Open transaction on database Open object store on transaction Perform operation on object store A transaction can be thought of as a safe wrapper around an operation or group of operations. If one of the actions within a transaction fail, all of the actions are rolled back. Transactions are specific to one or more object stores, which we define when we open the transaction. They can be read-only or read and write. This signifies whether the operations inside the transaction read the data or make a change to the database.

. - Creating data

To create data, call the add method on the object store and pass in the data you want to add. Add has an optional second argument that lets you define the primary key for the individual object on creation, but it should only be used if you have not specified the key path in createObjectStore. Here is a simple example: someObjectStore.add(data, optionalKey); The data parameter can be data of any type: a string, number, object, array, and so forth. The only restriction is if the object store has a defined keypath, the data must contain this property and the value must be unique. The add method returns a promise that resolves once the object has been added to the store. Add occurs within a transaction, so even if the promise resolves successfully it doesn't necessarily mean the operation worked. Remember, if one of the actions in the transaction fails, all of the operations in the transaction are rolled back. To be sure that the add operation was carried out, we need to check if the whole transaction has completed using the transaction.complete method. transaction.complete is a promise that resolves when the transaction completes and rejects if the transaction errors. Note that this method doesn't actually close the transaction. The transaction completes on its own. We must perform this check for all "write" operations, because it is our only way of knowing that the changes to the database have actually been carried out. Let's look at an example of the add method: dbPromise.then(function(db) { var tx = db.transaction('store', 'readwrite'); var store = tx.objectStore('store'); var item = { name: 'sandwich', price: 4.99, description: 'A very tasty sandwich', created: new Date().getTime() }; store.add(item); return tx.complete; }).then(function() { console.log('added item to the store os!'); }); First, we get the database object. We call .then on dbPromise, which resolves to the database object, and pass this object to the callback function in .then. Because dbPromise (idb.open) is a promise, we can safely assume that when .then executes, the database is open and all object stores and indexes are ready for use. The next step is to open a transaction by calling the transaction method on the database object. This method takes a list of object stores, which defines the scope of the transaction (if it is a single store name, we can pass it directly instead of passing an array of names, as we did in our example where we only want the "store" object store). The transaction method also has an optional second argument for the mode, which can be readonly or readwrite. This option is read-only by default. We can then open the "store" object store on this transaction and assign it to the store variable. Now when we call store.add, the add operation occurs within the transaction. Finally, we return tx.complete and log a success message once the transaction has completed.

. - Reading data

To read data, call the get method on the object store. The get method takes the primary key of the object you want to retrieve from the store. Here is a basic example: someObjectStore.get(primaryKey); As with add, the get method returns a promise and must happen within a transaction. Let's look at an example of the get method: dbPromise.then(function(db) { var tx = db.transaction('store', 'readonly'); var store = tx.objectStore('store'); return store.get('sandwich'); }).then(function(val) { console.dir(val); }); Once again, we start the operation by getting the database object and creating a transaction. Note that this time it is a read-only transaction because we are not writing anything to the database inside the transaction (that is, using put, add, or delete). We then open the object store on the transaction and assign the resulting object store object to the store variable. Finally, we return the result of store.get and log this object to the console.

. - Updating data

To update data, call the put method on the object store. The put method is very similar to the add method and can be used instead of add to create data in the object store. Like add, put takes the data and an optional primary key: someObjectStore.put(data, optionalKey); Again, this method returns a promise and occurs inside a transaction. As with add, we need to be careful to check transaction.complete if we want to be sure that the operation was actually carried out. Here is an example using the put method: dbPromise.then(function(db) { var tx = db.transaction('store', 'readwrite'); var store = tx.objectStore('store'); var item = { name: 'sandwich', price: 99.99, description: 'A very tasty, but quite expensive, sandwich', created: new Date().getTime() }; store.put(item); return tx.complete; }).then(function() { console.log('item updated!'); }); To update an existing item in the object store, use the put method on an object containing the same primary key value as the object in the store. We are assuming the keyPath for the store object store is the "name" property and we are updating the price and description of our "sandwich" object. The database interaction has the same structure as the create and read operations: get the database object, create a transaction, open an object store on the transaction, perform the operation on the object store.

. - Deleting data

To delete data, call the delete method on the object store. someObjectStore.delete(primaryKey); Once again, this method returns a promise and must be wrapped in a transaction. Here is a simple example: dbPromise.then(function(db) { var tx = db.transaction('store', 'readwrite'); var store = tx.objectStore('store'); store.delete(key); return tx.complete; }).then(function() { console.log('Item deleted'); }); The structure of the database interaction is the same as for the other operations. Note that we again check that the whole transaction has completed by returning the tx.complete method to be sure that the delete was carried out.

Getting all the data

So far we have only retrieved objects from the store one at a time. We can also retrieve all of the data (or subset) from an object store or index using either the getAll method or using cursors.

. - Using the getAll method

The simplest way to retrieve all of the data is to call the getAll method on the object store or index, like this: someObjectStore.getAll(optionalConstraint); This method returns all the objects in the object store matching the specified key or key range, or all objects in the store if no parameter is given. As with all other database operations, this operation happens inside a transaction. Here is a short example: dbPromise.then(function(db) { var tx = db.transaction('store', 'readonly'); var store = tx.objectStore('store'); return store.getAll(); }).then(function(items) { console.log('Items by name:', items); }); Here we are calling getAll on the "store" object store. This returns all of the objects in the store ordered by the primary key.

. - Using cursors

Another way to retrieve all of the data is to use a cursor. A cursor selects each object in an object store or index one by one, letting you do something with the data as it is selected. Cursors, like the other database operations, work within transactions. We create the cursor by calling the openCursor method on the object store, like this: someObjectStore.openCursor(optionalKeyRange, optionalDirection); This method returns a promise that resolves with a cursor object representing the first object in the object store or undefined if there is no object. To move on to the next object in the object store, we call cursor.continue. This returns a promise that resolves with the next object, or undefined if there are no more objects. We put this inside a loop to move through all of the entries in the store one by one. The optional key range in the openCursor method limits the iteration to a subset of the objects in the store. The direction option can be next or prev, specifying forward or backward traversal through the data. The next example uses a cursor to iterate through all the items in the "store" object store and log them to the console: dbPromise.then(function(db) { var tx = db.transaction('store', 'readonly'); var store = tx.objectStore('store'); return store.openCursor(); }).then(function logItems(cursor) { if (!cursor) { return; } console.log('Cursored at:', cursor.key); for (var field in cursor.value) { console.log(cursor.value[field]); } return cursor.continue().then(logItems); }).then(function() { console.log('Done cursoring'); }); As usual, we start by getting the database object, creating a transaction, and opening an object store. We call the openCursor method on the object store and pass the cursor object to the callback function in .then. This time we name the callback function "logItems" so we can call it from inside the function and make a loop. The line if (!cursor) {return;} breaks the loop if the promise returned by store.openCursor() resolves with undefined, or if the promise returned by cursor.continue()resolves with undefined (indicating that there are no more objects). The cursor object contains a key property that represents the primary key for the item. It also contains a value property that represents the data. At the end of logItems, we return cursor.continue().then(logItems). The cursor.continue method returns a promise that resolves to a cursor object representing the next item in the store or undefined if there are no more objects. This result is passed to the callback function in .then, which we have chosen to be logItems,so that the function loops. Consequently, logItems continues to call itself until no objects remain.

. - Working with ranges and indexes

We can get all the data in a couple of different ways, but what if we want only a subset of the data based on a particular property? This is where indexes come in. Indexes let us fetch the data in an object store by a property other than the primary key. We can create an index on any property (which becomes the keypath for the index), specify a range on that property, and get the data within the range using the getAll method or a cursor. We define the range using the IDBKeyRange object. This object has four methods that are used to define the limits of the range: upperBound, lowerBound, bound (which means both), and only. As expected, the upperBound and lowerBound methods specify the upper and lower limits of the range. IDBKeyRange.lowerBound(indexKey); Or IDBKeyRange.upperBound(indexKey); They each take one argument which is be the index's keypath value of the item you want to specify as the upper or lower limit. The bound method is used to specify both an upper and lower limit, and takes the lower limit as the first argument: IDBKeyRange.bound(lowerIndexKey, upperIndexKey); The range for these functions is inclusive by default, but can be specified as exclusive by passing true as the second argument (or the third and fourth in the case of bound, for the lower and upper limits respectively). An inclusive range includes the data at the limits of the range. An exclusive range does not. Let's look at an example. For this demo, we have created an index on the "price" property in the "store" object store. We have also added a small form with two inputs for the upper and lower limits of the range. Imagine we are passing in the lower and upper bounds to the function as floating point numbers representing prices: function searchItems(lower, upper) { if (lower === ' && upper === ') {return;} var range; if (lower !== ' && upper !== ') { range = IDBKeyRange.bound(lower, upper); } else if (lower === ') { range = IDBKeyRange.upperBound(upper); } else { range = IDBKeyRange.lowerBound(lower); } dbPromise.then(function(db) { var tx = db.transaction(['store'], 'readonly'); var store = tx.objectStore('store'); var index = store.index('price'); return index.openCursor(range); }).then(function showRange(cursor) { if (!cursor) {return;} console.log('Cursored at:', cursor.key); for (var field in cursor.value) { console.log(cursor.value[field]); } return cursor.continue().then(showRange); }).then(function() { console.log('Done cursoring'); }); } The code first gets the values for the limits and checks if the limits exist. The next block of code decides which method to use to limit the range based on the values. In the database interaction, we open the object store on the transaction as usual, then we open the "price" index on the object store. The "price" index allows us to search for the items by price. We open a cursor on the index and pass in the range. The cursor now returns a promise representing the first object in the range, or undefined if there is no data within the range. cursor.continue returns a cursor a object representing the next object and so on through the loop until we reach the end of the range.

Using database versioning

When we call idb.open, we can specify the database version number in the second parameter. If this version number is greater than the version of the existing database, the upgrade callback executes, allowing us to add object stores and indexes to the database. The UpgradeDB object has a special oldVersion property, which indicates the version number of the database existing in the browser. We can pass this version number into a switch statement to execute blocks of code inside the upgrade callback based on the existing database version number. Let's look at an example: var dbPromise = idb.open('test-db7', 2, function(upgradeDb) { switch (upgradeDb.oldVersion) { case 0: upgradeDb.createObjectStore('store', {keyPath: 'name'}); case 1: var peopleStore = upgradeDb.transaction.objectStore('store'); peopleStore.createIndex('price', 'price'); } }); In the example we have set the newest version of the database at 2. When this code first executes, since the database doesn't yet exist in the browser, upgradeDb.oldVersion is 0 and the switch statement starts at case 0. In our example, this results in a "store" object store being added to the database. Usually, in switch statements, there is a break after each case, but we are deliberately not doing that here. This way, if the existing database is a few versions behind (or if it doesn't exist), the code continues through the rest of the case blocks until it has executed all the latest changes. So in our example, the browser continues executing through case 1, creating a "price" index on the "store" object store. Once this has finished executing, the database in the browser is at version 2 and contains a "store" object store with a "price" index. Let's say we now want to create a "description" index on the "store" object store. We need to update the version number and add a case, like this: var dbPromise = idb.open('test-db7', 3, function(upgradeDb) { switch (upgradeDb.oldVersion) { case 0: upgradeDb.createObjectStore('store', {keyPath: 'name'}); case 1: var storeOS = upgradeDb.transaction.objectStore('store'); storeOS.createIndex('price', 'price'); case 2: var storeOS = upgradeDb.transaction.objectStore('store'); storeOS.createIndex('description', 'description'); } }); Assuming the database we created in the previous example still exists in the browser, when this executes upgradeDb.oldVersion is 2. case 0 and case 1 are skipped and the browser executes the code in case 2, which creates a "description" index. Once all this has finished, the browser has a database at version 3 containing a "store" object store with "price" and "description" indexes.

Further reading

. - IndexedDB Documentation

Using IndexedDB - MDN Basic Concepts Behind indexedDB - MDN Indexed Database API - W3C

. - Data storage limits

Working with quota on mobile browsers Browser storage limits and eviction criteria

Appendix

. - Comparison of IndexedDB API and IndexedDB Promised library

The IndexedDB Promised library sits on top of the IndexedDB API, translating its requests into promises. The overall structure is the same between the library and the API and, in general, the actual syntax for the database operations is the same and they will act the same way. But there are a few differences because of the differences between requests and promises, which we will cover here. All database interactions in the IndexedDB API are requests and have associated onsuccess and onerror event handlers. These are similar to the .then and .catch promise functions. The indexedDB.open method in the raw API also gets a special event handler, onupgradeneeded, which is used to create the object stores and indexes. This is equivalent to the upgrade callback in idb.open in the Promised library. In fact, if you look through the Promised library, you will find the upgrade callback is just a convenient wrapper for the onupgradeneeded event handler. Let's look at an example of the IndexedDB API. In this example we will open a database, add an object store, and add one item to the object store: var db; var openRequest = indexedDB.open('test_db', 1); openRequest.onupgradeneeded = function(e) { var db = e.target.result; console.log('running onupgradeneeded'); if (!db.objectStoreNames.contains('store')) { var storeOS = db.createObjectStore('store', {keyPath: 'name'}); } }; openRequest.onsuccess = function(e) { console.log('running onsuccess'); db = e.target.result; addItem(); }; openRequest.onerror = function(e) { console.log('onerror!'); console.dir(e); }; function addItem() { var transaction = db.transaction(['store'], 'readwrite'); var store = transaction.objectStore('store'); var item = { name: 'banana', price: '$2.99', description: 'It is a brown banana!', created: new Date().getTime() }; var request = store.add(item); request.onerror = function(e) { console.log('Error', e.target.error.name); }; request.onsuccess = function(e) { console.log('Woot! Did it'); }; } This code does something very similar to previous examples in this tutorial except that it doesn't use the Promised library. We can see that the structure of the database interaction hasn't changed. Object stores are created on the database object in the upgrade event handler, and items are added to the object store in the same transaction sequence we've seen before. The difference is that this is done with requests and event handlers rather than promises and promise chains. Here is a short reference of the differences between the IndexedDB API and the IndexedDB Promised library.
IndexedDB Promised IndexedDB API
Open database idb.open(name, version, upgradeCallback) indexedDB.open(name, version)
Upgrade database Inside upgradeCallback request.onupgradeneeded
Success .then request.onsuccess
Error .catch request.onerror

IndexedDB Starter Tutorial

Characteristics of IndexedDB are as follows: (1) It's stored in key-value pairs. IndexedDB uses an object store to hold data internally. All types of data can be stored in directly, including JavaScript objects. In the object store, the data is stored in the form of "key-value pairs". Each data record has its own corresponding primary key, and the primary key is unique and can't be repeated, otherwise an error will be thrown. (2) Asynchronous. It won't lock the browser when you are operating IndexedDB, and users can still perform other operations, which is in contrast to LocalStorage (as it's synchronous). Asynchronous design is to prevent the reading and writing of large amounts of data, which will slow down the performance of web pages. (3) Support transaction. IndexedDB supports transactions, which means that as long as one of a series of the steps fails, the entire transaction will be canceled, and the database is rolled back to the state before the transaction occurred. So there is no case where only a part of the data is rewritten. (4) Homologous restriction. IndexedDB is subject to homology restriction, and each database corresponds to the domain name that created it. The web page can only access the database which is under its own domain name, but not a cross-domain database. (5) Large storage space. IndexedDB has a much larger storage space than LocalStorage. Generally it's more than 250MB, or even no upper limit. (6) Support binary storage. IndexedDB can store not only strings, but also binary data (ArrayBuffer objects and Blob objects).

. - 2. Basic concepts

IndexedDB is a more complex API, and there are many concepts. It abstracts different entities into individual object interfaces. To learning the API is to learn its various object interfaces. Database: IDBDatabase object Object store: IDBObjectStore object Index: IDBIndex object Transaction: IDBTransaction object Operation request: IDBRequest object Pointer: IDBCursor object Primary key collection: IDBKeyRange object Here are some of the main concepts. Database -> Object store -> Data recording (1) Database A database is a collection of related data. Each domain name (strictly speaking, protocol + domain name + port) can create any number of databases. The IndexedDB database has the concept of a version. only one version of the database can exist at the same time. If you want to modify the database structure (add or delete tables, indexes or primary keys), you can only do this by upgrading the database version. (2) Object store Each database contains several object stores. It is similar to the table in the relational database. (3) Data recording Object store holds data record. Each record is similar to the row of a relational database, but with only the primary key and the data body. The primary key is used to establish the default index, which must be different, otherwise an error will be thrown. The primary key can be an attribute in the data record, and it also can be specified as an incremental integer number. { id: 1, text: 'foo' } In the above object, the id attribute can be treated as a primary key. The data body can be any data type and is not limited to objects. (4) Index In order to speed up the retrieval of data, you can build indexes for different attributes inside the object store. (5) Transaction It should be done through transaction when you need to read, write or delete data records. It provides three events, which are error, abort and complete on the transaction objects to listen for the result of the operation.

. - 3. Operation process

IndexedDB database are generally performed by the following process. This section only gives a simple code example for quick start-up. For more detailed API for each object, see here.

. - 3.1 Open the database

The first step to use IndexedDB is to open the database, which is to use indexedDB.open() method. var request = indexedDB.open(databaseName, version); The method takes two arguments, and the first argument which represents the name of the database is a string. If the specified database doesn't exist, a new database will be created. The second argument is an integer representing the version of the database. If omitted, when opening an existing database, the default is the current version; when creating a new database, the default is 1. The indexedDB.open() method returns an IDBRequest object. The object handles the operation result for opening the database through three events error, success, upgradeneeded. (1) error event The error event indicates that it failed to open the database. request.onerror = function (event) { console.log('The database is opened failed'); }; (2) success event The success event indicates that the database was opened successfully. var db; request.onsuccess = function (event) { db = request.result; console.log('The database is opened successfully'); }; At this point, the database object is obtained by the result attribute of the request object. (3) upgradeneeded event If the specified version number is greater than the actual version number of the database, a database upgrade event upgradeneeded occurs. var db; request.onupgradeneeded = function (event) { db = event.target.result; } At this point, the database instance is obtained through the target.result attribute of the event object.

. - 3.2 Creating a new database

Creating a new database is the same as opening a database. If the specified database doesn't exist, it will create a new one. The difference is that the subsequent operations are mainly done in the listener of the upgradeneeded event. The reason why the event is triggered is that the version comes from scratch. Usually, after creating a new database, the first thing is to create a new object store (create a new table). request.onupgradeneeded = function(event) { db = event.target.result; var objectStore = db.createObjectStore('person', { keyPath: 'id' }); } In the above code, after the database is created successfully, a new table called person is added, and the primary key is id. A better way to do this is to first determine whether the table exists, and if it doesn't exist, create a new one then. request.onupgradeneeded = function (event) { db = event.target.result; var objectStore; if (!db.objectStoreNames.contains('person')) { objectStore = db.createObjectStore('person', { keyPath: 'id' }); } } The primary key is the index attribute which is built by default. For example, the data record is { id: 1, name: 'Jam' }, so the id attribute can be used as the primary key. The property of the objects in the next layer can also be specified as the primary key. For example, the foo.bar of the{ foo: { bar: 'baz' } } can also be specified as the primary key. If there is no suitable attribute in the data record as a primary key, then you can make IndexedDB generated a primary key automatically. var objectStore = db.createObjectStore( 'person', { autoIncrement: true } ); In the above code, the specified primary key is an increasing integer. After creating a new object store, the next step is to create a new index. request.onupgradeneeded = function(event) { db = event.target.result; var objectStore = db.createObjectStore('person', { keyPath: 'id' }); objectStore.createIndex('name', 'name', { unique: false }); objectStore.createIndex('email', 'email', { unique: true }); } In the above code, the three parameters of IDBObject.createIndex() are the index name, the attribute of the index and the configuration object (indicating whether the attribute contains duplicate values).

. - 3.3 Add data

Adding data refers to writing data records to an object store. It needs to be done through the transaction. function add() { var request = db.transaction(['person'], 'readwrite') .objectStore('person') .add({ id: 1, name: 'Jam', age: 24, email: 'jam@example.com' }); request.onsuccess = function (event) { console.log('The data has been written successfully'); }; request.onerror = function (event) { console.log('The data has been written failed'); } } add(); In the above code, you need to create a new transaction in order to write data. The table name and operating mode ("Read Only" or "Read and Write") must be specified when creating. After the new transaction is created, you can use IDBTransaction.objectStore(name) method to obtain the IDBObjectStore object, and then use add()method on the table object to write a record to the table. The operation of writing is asynchronous, and it can be known whether it was written successfully by listening to the success and error events on the connection object.

. - 3.4 Read data

Reading data is also done through transactions. function read() { var transaction = db.transaction(['person']); var objectStore = transaction.objectStore('person'); var request = objectStore.get(1); request.onerror = function(event) { console.log('Transaction failed'); }; request.onsuccess = function( event) { if (request.result) { console.log('Name: ' + request.result.name); console.log('Age: ' + request.result.age); console.log('Email: ' + request.result.email); } else { console.log('No data record'); } }; } read(); In the above code, the objectStore.get() method is used to read data, and the parameter is the value of the primary key.

. - 3.5 Traverse data

To traverse all the records of the data table, you should use the pointer object IDBCursor. function readAll() { var objectStore = db.transaction('person').objectStore('person'); objectStore.openCursor().onsuccess = function (event) { var cursor = event.target.result; if (cursor) { console.log('Id: ' + cursor.key); console.log('Name: ' + cursor.value.name); console.log('Age: ' + cursor.value.age); console.log('Email: ' + cursor.value.email); cursor.continue(); } else { console.log('No more data'); } }; } readAll(); In the above code, the openCursor() method of the new pointer object is an asynchronous operation, so you need to listen to the success event.

. - 3.6 Update data

The IDBObject.put() method is used to update data. function update() { var request = db.transaction(['person'], 'readwrite') .objectStore('person') .put({ id: 1, name: 'Jim', age: 35, email: 'Jim@example.com' }); request.onsuccess = function (event) { console.log('The data has been updated successfully'); }; request.onerror = function (event) { console.log('The data has been updated failed'); } } update(); In the above code, the put() method updates the record of which the primary key is 1 automatically.

. - 3.7 Delete data

The IDBObjectStore.delete() method is used to delete records. function remove() { var request = db.transaction(['person'], 'readwrite') .objectStore('person') .delete(1); request.onsuccess = function (event) { console.log('The data has been deleted successfully'); }; } remove();

. - 3.8 Index

The role of an index is to allow you to search for any field, that is, get data record from any field. If you haven't built an index, you can only search for the primary key by default ( take values from the primary key). Assume that you have built an index for the name field when creating a new table. objectStore.createIndex('name', 'name', { unique: false }); Now, you can find the corresponding data record from the name. var transaction = db.transaction(['person'], 'readonly'); var store = transaction.objectStore('person'); var index = store.index('name'); var request = index.get('Jim'); request.onsuccess = function (e) { var result = e.target.result; if (result) { // ... } else { // ... } }

enter into an IndexedDB

https://www.tutorialspoint.com/html5/html5_indexeddb.htm Before enter into an indexeddb, we need to add some prefixes of implementation as shown below window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction; window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange if (!window.indexedDB) { window.alert("Your browser doesn't support a stable version of IndexedDB.") }

- Open an IndexedDB database

Before creating a database, we have to prepare some data for the data base.let's start with company employee details. const employeeData = [ { id: "01", name: "Gopal K Varma", age: 35, email: "contact@tutorialspoint.com" }, { id: "02", name: "Prasad", age: 24, email: "prasad@tutorialspoint.com" } ];

- Adding the data

Here adding some data manually into the data as shown below − function add() { var request = db.transaction(["employee"], "readwrite") .objectStore("employee") .add({ id: "01", name: "prasad", age: 24, email: "prasad@tutorialspoint.com" }); request.onsuccess = function(event) { alert("Prasad has been added to your database."); }; request.onerror = function(event) { alert("Unable to add data\r\nPrasad is already exist in your database! "); } }

- Retrieving Data

We can retrieve the data from the data base using with get() function read() { var transaction = db.transaction(["employee"]); var objectStore = transaction.objectStore("employee"); var request = objectStore.get("00-03"); request.onerror = function(event) { alert("Unable to retrieve daa from database!"); }; request.onsuccess = function(event) { if(request.result) { alert("Name: " + request.result.name + ", Age: " + request.result.age + ", Email: " + request.result.email); } else { alert("Kenny couldn't be found in your database!"); } }; } Using with get(), we can store the data in object instead of that we can store the data in cursor and we can retrieve the data from cursor. function readAll() { var objectStore = db.transaction("employee").objectStore("employee"); objectStore.openCursor().onsuccess = function(event) { var cursor = event.target.result; if (cursor) { alert("Name for id " + cursor.key + " is " + cursor.value.name + ", Age: " + cursor.value.age + ", Email: " + cursor.value.email); cursor.continue(); } else { alert("No more entries!"); } }; }

- Removing the data

We can remove the data from IndexedDB with remove().Here is how the code looks like function remove() { var request = db.transaction(["employee"], "readwrite") .objectStore("employee") .delete("02"); request.onsuccess = function(event) { alert("prasad entry has been removed from your database."); }; }

- HTML Code

To show all the data we need to use onClick event as shown below code − <!DOCTYPE html> <html> <head> <meta http-equiv = "Content-Type" content = "text/html; charset = utf-8" /> <title>IndexedDb Demo | onlyWebPro.com</title> </head> <body> <button onclick = "read()">Read </button> <button onclick = "readAll()"></button> <button onclick = "add()"></button> <button onclick = "remove()">Delete </button> </body> </html> The final code should be as − <!DOCTYPE html> <html> <head> <meta http-equiv = "Content-Type" content = "text/html; charset = utf-8" /> <script type = "text/javascript"> //prefixes of implementation that we want to test window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; //prefixes of window.IDB objects window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction; window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange if (!window.indexedDB) { window.alert("Your browser doesn't support a stable version of IndexedDB.") } const employeeData = [ { id: "00-01", name: "gopal", age: 35, email: "gopal@tutorialspoint.com" }, { id: "00-02", name: "prasad", age: 32, email: "prasad@tutorialspoint.com" } ]; var db; var request = window.indexedDB.open("newDatabase", 1); request.onerror = function(event) { console.log("error: "); }; request.onsuccess = function(event) { db = request.result; console.log("success: "+ db); }; request.onupgradeneeded = function(event) { var db = event.target.result; var objectStore = db.createObjectStore("employee", {keyPath: "id"}); for (var i in employeeData) { objectStore.add(employeeData[i]); } } function read() { var transaction = db.transaction(["employee"]); var objectStore = transaction.objectStore("employee"); var request = objectStore.get("00-03"); request.onerror = function(event) { alert("Unable to retrieve daa from database!"); }; request.onsuccess = function(event) { // Do something with the request.result! if(request.result) { alert("Name: " + request.result.name + ", Age: " + request.result.age + ", Email: " + request.result.email); } else { alert("Kenny couldn't be found in your database!"); } }; } function readAll() { var objectStore = db.transaction("employee").objectStore("employee"); objectStore.openCursor().onsuccess = function(event) { var cursor = event.target.result; if (cursor) { alert("Name for id " + cursor.key + " is " + cursor.value.name + ", Age: " + cursor.value.age + ", Email: " + cursor.value.email); cursor.continue(); } else { alert("No more entries!"); } }; } function add() { var request = db.transaction(["employee"], "readwrite") .objectStore("employee") .add({ id: "00-03", name: "Kenny", age: 19, email: "kenny@planet.org" }); request.onsuccess = function(event) { alert("Kenny has been added to your database."); }; request.onerror = function(event) { alert("Unable to add data\r\nKenny is aready exist in your database! "); } } function remove() { var request = db.transaction(["employee"], "readwrite") .objectStore("employee") .delete("00-03"); request.onsuccess = function(event) { alert("Kenny's entry has been removed from your database."); }; } </script> </head> <body> <button onclick = "read()">Read </button> <button onclick = "readAll()">Read all </button> <button onclick = "add()">Add data </button> <button onclick = "remove()">Delete data </button> </body> </html> It will produce the following output − thePage

Working example

Working example of an IndexedDB implementation to handle transactions surrounding a fake invoice database https://gist.github.com/ryandabler/41c458871cb6b64f599fb182ba88daba IndexedDB example.js const request = window.indexedDB.open("database", 1); // Create schema request.onupgradeneeded = event => { const db = event.target.result; const invoiceStore = db.createObjectStore("invoices", { keyPath: "invoiceId" }); invoiceStore.createIndex("VendorIndex", "vendor"); const itemStore = db.createObjectStore("invoice-items", { keyPath: ["invoiceId", "row"] }); itemStore.createIndex("InvoiceIndex", "invoiceId"); const fileStore = db.createObjectStore("attachments", { autoIncrement: true }); fileStore.createIndex("InvoiceIndex", "invoiceId"); }; request.onsuccess = () => { const db = request.result; const transaction = db.transaction(["invoices", "invoice-items"], "readwrite"); const invStore = transaction.objectStore("invoices"); const itemStore = transaction.objectStore("invoice-items"); const invIndex = invStore.index("VendorIndex"); // Add data invStore.add({invoiceId: "123", vendor: "Whirlpool", paid: false}); itemStore.add({invoiceId: "123", row: "1", item: "Dish washer", cost: 1400}); itemStore.add({invoiceId: "123", row: "2", item: "Labor", cost: 500}); invStore.add({invoiceId: "580", vendor: "Whirlpool", paid: true}); itemStore.add({invoiceId: "580", row: "1", item: "Rubber hose", cost: 20}); // Update an item itemStore.put({invoiceId: "123", row: "1", item: "Dish washer", cost: 1300}); // Delete an item itemStore.delete(["123", "2"]); // Get an item by key const getRequest = invStore.get("123"); getRequest.onsuccess = () => { console.log(getRequest.result); // {invoiceId: "123", vendor: "Whirlpool", paid: false} }; // Get an item by index const getRequestIdx = invIndex.getAll("Whirlpool"); getRequestIdx.onsuccess = () => { console.log(getRequestIdx.result); // [ {invoiceId: "123", vendor: "Whirlpool", paid: false}, }; // {invoiceId: "580", vendor: "Whirlpool", paid: true} ] };

Summary

Open database: indexedDB.open(name, version) Upgrade database: request.onupgradeneeded Success: request.onsuccess Error: request.onerror var dbase; var request = indexedDB.open("testDB", 2); request.onerror = function(evt){ console.log("DB Open Error", evt); } request.onupgradeneeded = function(evt){ dbase = request.result; var objectStore = dbase.createObjectStore("students", { keyPath : "rollNo" }); }; request.onupgradeneeded = function(event) { dbase = event.target.result; var objectStore = dbase.createObjectStore('person', { keyPath: 'id' }); objectStore.createIndex('name', 'name', { unique: false }); objectStore.createIndex('email', 'email', { unique: true }); } request.onsuccess = function(evt){ dbase = request.result; } function add() { var request = dbase.transaction(['person'], 'readwrite') .objectStore('person') .add({ id: 1, name: 'Jam', age: 24, email: 'jam@example.com' }); request.onsuccess = function (event) { console.log('The data has been written successfully'); }; request.onerror = function (event) { console.log('The data has been written failed'); } } add(); function read() { var transaction = dbase.transaction(['person']); var objectStore = transaction.objectStore('person'); var request = objectStore.get(1); request.onerror = function(event) { console.log('Transaction failed'); }; request.onsuccess = function( event) { if (request.result) { console.log('Name: ' + request.result.name); console.log('Age: ' + request.result.age); console.log('Email: ' + request.result.email); } else { console.log('No data record'); } }; } read(); function readAll() { var objectStore = dbase.transaction('person').objectStore('person'); objectStore.openCursor().onsuccess = function (event) { var cursor = event.target.result; if (cursor) { console.log('Id: ' + cursor.key); console.log('Name: ' + cursor.value.name); console.log('Age: ' + cursor.value.age); console.log('Email: ' + cursor.value.email); cursor.continue(); } else { console.log('No more data'); } }; } readAll(); function update() { var request = dbase.transaction(['person'], 'readwrite') .objectStore('person') .put({ id: 1, name: 'Jim', age: 35, email: 'Jim@example.com' }); request.onsuccess = function (event) { console.log('The data has been updated successfully'); }; request.onerror = function (event) { console.log('The data has been updated failed'); } } update(); function remove() { var request = dbase.transaction(['person'], 'readwrite') .objectStore('person') .delete(1); request.onsuccess = function (event) { console.log('The data has been deleted successfully'); }; } remove(); find the corresponding data record from the name. var transaction = dbase.transaction(['person'], 'readonly'); var store = transaction.objectStore('person'); var index = store.index('name'); var request = index.get('Jim'); request.onsuccess = function (e) { var result = e.target.result; if (result) { // ... } else { // ... } }