IndexedDB

Indexing enables efficient searches of data.

IndexedDB is organized into structured indexed databases.

A database contains object stores (comparable to tables in SQL), which in turn contain objects or other types of data.

An object store can be structured in 4 ways:

keyPath autoIncrement
(none) false The object store can hold any value. You must supply a separate key argument whenever you want to add a new value.
'key' false The object store can only hold objects. The object must have a property with the same name as the key path.
(none) true The object store can hold any value. The key is generated for you automatically, or you can supply a separate key argument if you want to use a specific key.
'key' true The object store can only hold objects. Usually, a key is generated and the value of the generated key is stored in the object in a property with the same name as the key path. If such a property already exists, the value of that property is used as the key rather than generating a new key.

The operations for IndexedDB are mostly asynchronous, which means that before a function returns, other code may continue.

Note that window.indexedDB implements IDBFactory.

IDBFactory
Methods:
IDBOpenDBRequest open(String dbName, int version)
IDBOpenDBRequest delete(String dbName)
int cmp(Any a, Any b)

IDBOpenDBRequest
Inherits: IDBRequest
Handlers:
function(e) onblocked
function(e) onupgradeneeded

IDBDatabase
Inherits: EventTarget
Properties:
String name
int version version
DOMStringList objectStoreNames
Handlers:
function(e) onabort
function(e) onerror
function(e) onversionchange
Methods:
void close()
IDBObjectStore createObjectStore(String name, Object opt)
void deleteObjectStore(String name)
IDBTransaction transaction(String[] stores[, String mode]) ... mode : 'readwrite', 'readonly', 'versionchange'

IDBRequest
Inherits: EventTarget
Properties:
IDBObjectStore result
DOMError error
Object source
IDBTransaction transaction
IDBRequestReadyState readyState
Handlers:
function(e) onerror
function(e) onsuccess

IDBTransaction
Inherits: EventTarget
Properties:
IDBDatabase db
IDBTransaction
Mode mode
DOMError error
Methods:
void abort()
IDBObjectStore objectStore(String name)
Handlers:
function(e) onabort
function(e) oncomplete
function(e) onerror

IDBObjectStore
Properties:
DOMStringList indexNames
Any keyPath
String name
IDBTransaction transaction
Boolean autoIncrement
Methods:
IDBRequest add(Any item [, Any key])
IDBRequest clear()
IDBRequest delete(Any key)
IDBRequest get(Any key)
IDBIndex createIndex(String index, Any key[, Object options])
void deleteIndex(String index)
IDBIndex IDBRequest index(String index)
IDBRequest put(Any item [,Any key])
IDBRequest openCursor([KeyRange r [, String direction]])

IDBIndex
Inherits: EventTarget
Properties:
String name
IDBObjectStore objectStore
Any keyPath
Boolean multiEntry
Boolean unique
Methods:
IDBRequest count()
IDBRequest get(Any key)
IDBRequest getKey(Any key)
IDBRequest openCursor()
IDBRequest openKeyCursor()

IDBCursor
Properties:
IDBObjectStore/IDBIndex source
String direction
Any key
Any primaryKey
Methods:
void advance(int positions)
void continue([Any key])
IDBRequest delete()
IDBRequest update(Any new)

IDBCursorWithValue
Inherits: IDBCursor
Properties:
Any value

IDBKeyRange
Properties:
Any lower
Any upper
Boolean lowerOpen
Boolean upperOpen
Methods:
IDBKeyRange bound(Any lower, Any upper, Boolean lowerOpen, Boolean upperOpen)
IDBKeyRange only(Any value)
IDBKeyRange lowerBound(Any value[, Boolean open])
IDBKeyRange upperBound(Any value[, Boolean open])

IDBVersionChangeEvent
Properties:
unsigned long long oldVersion
unsigned long long newVersion

RESETRUNFULL
<!DOCTYPE html><html><head><script>
   var db;
   const students = [
      {id:'H423498', name:'Mike', clss:'5D', age:11},
      {id:'A213132', name:'Bill', clss:'4H', age:10},
      {id:'H234324', name:'Paul', clss:'4H', age:7}];
   
   if(indexedDB){   //indexedDB.deleteDatabase('myDB');
      var request = indexedDB.open('myDB',3);
      request.onerror = function(e){
         alert("Why didn't you allow me to use IndexedDB?");
      };
      request.onsuccess = function(e){      // This event is fired after the ‘upgradeneeded’ event if the latter is ever fired.
         db = e.target.result;
      };
      request.onupgradeneeded = function(e){      // This event is fired when you create a new database or increase the version number. 
                                                  // Furthermore, you can only create object stores in this event.
         db = e.target.result;
         var os = db.createObjectStore('students', {keyPath:'id'});
         os.createIndex('name','name',{unique:true});
         os.createIndex('clss','clss',{unique:false});
         os.transaction.oncomplete = function(e){
            T = db.transaction(['students'],'readwrite');
            var sos = T.objectStore('students');
            for (i in students) {sos.add(students[i]);}
         };
      };
   }
   function addStudents(){
      var T = db.transaction(['students'],'readwrite');
      var sos = T.objectStore('students');
      sos.add({id:'C577564', name:'Alam', clss:'3A', age:10});
      sos.add({id:'C234464', name:'Alex', clss:'2B', age:8});
   }
   function removeStudents(){
      var T = db.transaction(['students'],'readwrite');
      var sos = T.objectStore('students');
      sos.delete('C577564');
      sos.delete('C234464');
   }
   function getStudent(){
      var sos = db.transaction(['students'],'readwrite').objectStore('students');
      var index = sos.index('name');
      index.get('Bill').onsuccess = function(e){  // access by index
         data = event.target.result;
         document.getElementsByTagName('p')[0].innerHTML = data.id + " " + data.name + " " +
                                                           data.clss + " " + data.age + "<br/>";
      }
   }
   function getStudents(){
      document.getElementsByTagName('p')[0].innerHTML="";
      var sos = db.transaction(['students'],'readwrite').objectStore('students');
      var index = sos.index('clss');     // access by index
      var range = IDBKeyRange.bound('1A','4H',false,false); // including 1A and 4H
      index.openCursor(range,'prev').onsuccess = function(e){
         var cursor = e.target.result;
         if (cursor){
            document.getElementsByTagName('p')[0].innerHTML += cursor.value.id + " " + cursor.key + " " +
                                                                cursor.value.clss+" "+cursor.value.age+"<br/>";
            cursor.continue();
         };
      };
   }
   function changeStudent(){
      var sos = db.transaction(['students'],'readwrite').objectStore('students');
      var request = sos.get('C577564');   // access by key
      request.onsuccess = function(e) {
         data = request.result;
         data.age = 9;
         request2 = sos.put(data);
      }
   }
   function printStudents(){
      document.getElementsByTagName('p')[0].innerHTML="";      // A transaction will become inactive if you return to the event loop without using it. 
      var T = db.transaction(['students'],'readwrite');        // 'T' here must not be declared globally once only.
      var sos = T.objectStore('students');
      sos.openCursor().onsuccess = function(e){ //access by key
         var cursor = e.target.result;
         if (cursor){
            document.getElementsByTagName('p')[0].innerHTML += cursor.key + " " + cursor.value.name + " " +
                                                               cursor.value.clss + " " + cursor.value.age + "<br/>";
            cursor.continue();
         };
      };
   }
   </script></head>
   <body style="height:200px">
      <p></p>
      <button onclick="addStudents();">Add students</button>
      <button onclick="removeStudents();">Remove students</button>
      <button onclick="getStudent();">Get by name</button>
      <button onclick="getStudents();">Get by class</button>
      <button onclick="changeStudent();">Change by id</button>
      <button onclick="printStudents();">Print students</button>
   </body></html>

As you can see, the syntax of IndexedDB can be not very intuitive. To ease development, consider using one of the following libraries:

Dexie.js: A wrapper for IndexedDB that allows much faster code development via nice, simple syntax.

ZangoDB: A MongoDB-like interface for IndexedDB that supports most of the familiar filtering, projection, sorting, updating, and aggregation features of MongoDB.

JsStore: An IndexedDB wrapper with SQL like syntax.

MiniMongo: A client-side in-memory mongodb backed by localstorage with server sync over HTTP. MiniMongo is used by MeteorJS.

PouchDB: A client-side implementation of CouchDB in the browser using IndexedDB

idb: A tiny (~1.15k) library that mostly mirrors the IndexedDB API, but with small improvements that make a big difference to usability.

idb-keyval: A super-simple-small (~600B) promise-based keyval store implemented with IndexedDB

sifrr-storage: A small (~2kB) promise based library for client-side key-value storage. Works with IndexedDB, localStorage, WebSQL, Cookies. Can automatically use supported storage available based on priority.

lovefield: Lovefield is a relational database for web apps. Written in JavaScript, works cross-browser. Provides SQL-like APIs that are fast, safe, and easy to use.