Loading a JSON file into IndexedDB

A script with a demonstration to fill an IDB database from a file and access the content.

An IndexedDB database consists of a list of key-values. So identifiers associated with objects that form the useful content: data or scripts ...

In fact the keys can be part of the contained objects, this is the case in our example, when we store JavaScript objects, which can come from JSON files exported from another database. We could also store scripts.

Sample data file:

{ "fruits": [
  {
	"name": "orange",	
	"color":"orange",
	"origin":"Asia",
	"content":"200"
  },
  {
	"name": "apple",  
	"color":"red, green, yellow",
	"origin":"Asia",
	"content":"1000"
  },
  {
	"name":"strawberry",   
	"color": "red",
	"origin": "France",
	"content":"50"
  },
  {
	"name":"blueberry",
	"color":"purple",
	"origin":"America",
	"content":"300"
  }
 ]
}

1) Loading the JSON file

async function loadJSON(fname) {
  var response = await fetch(fname)
  var str = await response.text()
  var data = JSON.parse(str)
  var idb = await importIDB("fruits", "fstore", data["fruits"])
  await displayIDB(idb, "fstore", "storage")
}

The JSON file is loaded as text and converted to an object with JSON.parse().

The function is declared async in order to be able to use await and thus wait until loading is finished to continue with the display of the contents.

2) Transferring its content to the database

function importIDB(dname, sname, arr) {
  return new Promise(function(resolve) {
    var r = window.indexedDB.open(dname)
    r.onupgradeneeded = function() {
      var idb = r.result
      var store = idb.createObjectStore(sname, {keyPath: "name"})
    }
    r.onsuccess = function() {
      var idb = r.result
        let tactn = idb.transaction(sname, "readwrite")
    	  var store = tactn.objectStore(sname)
        for(var obj of arr) {
          store.put(obj)
        }
        resolve(idb)
    }
    r.onerror = function (e) {
     alert("Enable to access IndexedDB, " + e.target.errorCode)
    }    
  })
}

The parameters of the importIDB function are the name of the database, the name of the table (store), and an array containing the list of objects to be stored in the table.

The database is open with the open method of indexedDB. A table is created with the createObjectStore method in a function associated with the onupgradeneeded event.

The keyPath: "name" option is intended to set the "name" property, which is part of every object stored in the database, as the search key. This is equivalent to the primary column in SQL.

When the database is successfully created, the success event is triggered and the contents of the associated function executed. We then open a transaction to access the table and store the records.

3) Showing the contents of the database

The function below is for a demonstration purpose only, to verify that the filling is done properly. In an application, the database is supposed to contain thousands of records, so its contents are not displayed in bulk.

However, it is useful to see how cursor can be used to browse the contents of the database, if you want to search and possibly use GraphQL queries.

function displayIDB(idb, sname, id) {
  let storage = document.getElementById(id)
  let tactn = idb.transaction(sname, "readonly")
  let osc = tactn.objectStore(sname).openCursor()
  osc.onsuccess = function(e) {
    let cursor = e.target.result
    if (cursor) {
      storage.innerHTML += "Name " + cursor.value["name"] + " : " + cursor.value["origin"] + " " + cursor.value["color"] + "<br>"
      cursor.continue()
    }
  } 
  tactn.oncomplete = function() {
    idb.close();
  }
}

It is still necessary to open a transaction to access the table of the recordings, and, a particularity of indexedDB, to use a "cursor", to parse the contents.
When the operation is complete, the oncomplete event is triggered and the database is closed (that is an option).

4) Accessing a record

async function getIDB(dname, sname, key) {
  return new Promise(function(resolve) {
    var r = indexedDB.open(dname)
      r.onsuccess = function(e) {
        var idb = r.result
        let tactn = idb.transaction(sname, "readonly")
        let store = tactn.objectStore(sname)
        let data = store.get(key)
        data.onsuccess = function() {
          resolve(data.result)
        }
        tactn.oncomplete = function() {
          idb.close()
        }
     }
  })
}

The database is opened again since it was closed in the previous function. A new transaction is performed and the store.get() method finds the record whose key is given.

This function returns a promise so that we can ensure that the data are available before displaying them. It depends on the function activated when we click on the button, which is the function below in our demo:

async function search() {
  var key = document.getElementById("searchval").value
  var infos = await getIDB("fruits", "fstore", key)
  document.getElementById("storage").innerHTML = JSON.stringify(infos, null, ' ')
}

The alternative is to use a callback.

The complete code is available in an archive to download:

To start the demo, load demoIDB.html locally in Firefox or another browser that accepts loading files from a local page.

See also: