Discuss IndexedDB ”; Previous Next Indexed Database is a type of NoSQL database or Non-relational structured query language. It is a transactional database system like an SQL-based RDBMS. However, unlike SQL-based RDBMSs, which use fixed-column tables, IndexedDB is a JavaScript-based object-oriented database. Print Page Previous Next Advertisements ”;
Category: indexeddb
IndexedDB – Transactions
IndexedDB – Transactions ”; Previous Next A transaction is a group of operations, that should either all succeed, or all fail. For example, if we pay from UPI to a merchant and the transaction declines then the money must fall back to the senders” account. A transaction maintains this integrity. Following is the syntax for opening a transaction − db.transaction(store[, type]); The store here is the object store where we want to do the transaction. The type of the transaction is of 2 types − read-only − can only read, by default it is given. read-write − we can only read and write the data but we cannot create, remove or alter it from object stores. Transaction life cycle The transaction is a connection between object stores to perform any operations. Each transaction has a state which can be − active − When a transaction is first created. or when a request is associated with a transaction. New requests can be made against the transaction when it is in this state. inactive − A transaction is in this state after control returns to the event after its creation. No requests can be made against the transaction when it is in this state. committing − Once all the requests associated with a transaction are completed then it attempts to commit. During the commit state, no new requests can be made. finished − After a transaction is committed or aborted then it is in the finished state. During the finished state, no new requests can be made. The lifetime of a transaction A transaction with a scope and a mode is formed. A transaction”s state is originally active when it is generated. To begin the transaction, the implementation must queue a task. A success or, error event will be fired when each request connected with a transaction is handled. The transaction state is set to active when the event is sent, allowing subsequent requests to be made against the transaction. The transaction”s status is set to inactive once the event dispatch is completed. A transaction can be canceled at any point before it is completed, even if it isn”t currently active or hasn”t begun. When all requests made against the database are successful, the implementation must attempt to commit the transaction. When a transaction is committed or aborted its state is set to finish. Transaction scheduling When a transaction can be started, there are some limitations. When there is no read or write transactions that: a. were established before transactions tx b. have an overlapping scope with tx c. are not in a final state, a read-only transaction tx can commence. A read/write-only transaction tx can begin when there are no other transactions that − were formed before tx, have an overlapping scope with tx, or are not in a completed state. Upgrade transactions A transaction with the mode “versionchange” is an upgrade transaction. Object stores and indexes in a database can be created, renamed, and deleted using upgrade operations. If a version greater than the current version is given, an upgrade transaction is automatically produced when completing the steps to run an upgrade transaction after a connection to a database is opened. Within the upgradeneeded event handler, this transaction will be active. Committing a transaction The following steps must be completed to commit a transaction − The transaction state is first set to committing. Wait until all of the transaction requests on the list have been processed. Abort the transaction if an error occurs. If the transaction is an upgrade transaction, set the database upgrade transaction”s transactions connections to NULL. Change the transaction state to complete. fire the transaction”s entire event If a transaction is an upgrade transaction, set the request”s transaction to null and make the request that is associated with the transaction. Syntax transaction.commit() Attempts to commit the transaction. All pending requests will be allowed to complete, but no new requests will be accepted. The transaction will abort if a pending request fails. The success events for successful requests will still fire, but throwing an exception in an event handler will not abort the transaction calling preventDefault() will not prevent the transaction from aborting. Event Handlers Various event handler attributes are as follows attribute EventHandler onabort; attribute EventHandler oncomplete; attribute EventHandler onerror; Transactions Example A simple JavaScript program to demonstrate the usage of a transaction is given below − <!DOCTYPE html> <html lang=”en”> <head> <title>Document</title> </head> <body> <script> const request = indexedDB.open(“botdatabase”,1); request.onupgradeneeded = function(){ const db = request.result; const store = db.createObjectStore(“bots”,{ keyPath: “id”}); } request.onsuccess = function(){ document.write(“database opened successfully”); const db = request.result; const transaction=db.transaction(“bots”,”readwrite”); const store = transaction.objectStore(“bots”); store.add({id: 1, name: “jason”,branch: “IT”}); store.add({id: 2, name: “praneeth”,branch: “CSE”}); store.add({id: 3, name: “palli”,branch: “EEE”}); store.add({id: 4, name: “abdul”,branch: “IT”}); store.put({id: 4, name: “deevana”,branch: “CSE”}); transaction.oncomplete = function(){ document.write(“transaction complete”); db.close; }; } </script> </body> </html> Output database opened successfully transaction complete Here a transaction is created, only when a transaction is created can we add data into the object store and finally after the transaction is complete we close the database. Example The following example shows the usage of a transaction attribute oncomplete − function student(db, names) { let transaction = db.transaction([”names”], ”readwrite”); let store = transaction.objectStore(”names”); for (let i = 0; i < messages.length; i++) { store.add({text: names[i]}); } transaction.oncomplete = function() {document.write(”transaction complete”)}; } Abort transactions To abort a transaction, follow these steps − All transaction-related modifications to the database are undone. Changes in object stores, indexes,
IndexedDB – Error Handling
IndexedDB – Error Handling ”; Previous Next Not all requests we write will return an output. This may happen due to − possible errors while writing the code. If the storage limit has been exceeded. If transactions have failed etc. In a failed request the transaction is canceled, and all the changes are reverted. But sometimes we want to handle the failure without reverting all the changes to do that we use the request.onerror handler. It can prevent the transaction abort by calling event.preventDefault(). Example An example to show error handling in IndexedDB is given below − <!DOCTYPE html> <html lang=”en”> <head> <title>IndexedDB</title> </head> <body> <script> const request = indexedDB.open(“DATABASE”, 1); request.onsuccess = function (){ document.write(“database creation success”) } request.onerror = function(event){ document.write(“Database not created ” + event.target.errorCode); } </script> </body> </html> Output Database not created undefined We can catch errors using the db.onerror handler for it. db.onerror = function(event) { let request = event.target; document.write(“Error is found”, request.error); }; The constraint error is occured when an object with the same id already exists. But sometimes if any of an error is fully handled and we don”t want to report it we can stop the bubbling by using event.stopPropagation() in request.onerror. request.onerror = function(event) { if (request.error.name == “ConstraintError”) { document.write(“id already exists”); event.preventDefault(); event.stopPropagation(); } } Print Page Previous Next Advertisements ”;
IndexedDB – Useful Resources
IndexedDB – Useful Resources ”; Previous Next The following resources contain additional information on IndexedDB. Please use them to get more in-depth knowledge on this. JavaScript Programming Training 47 Lectures 33 hours Uplatz More Detail Curso Mastering Google Chrome DevTools 60 Lectures 2.5 hours HECTOR URIEL PEREZ ROJAS More Detail Print Page Previous Next Advertisements ”;
IndexedDB – Promise Wrapper
IndexedDB – Promise Wrapper ”; Previous Next Promises, like callbacks, are a technique of telling what you want your code to perform once an asynchronous operation completes without stopping the runtime’s thread of javascript. Instead of supplying a callback to an asynchronous function to run after it completes, promises can be used instead. Promise library was created by Jake Archibald and it uses promises rather than events. It is easier to use than the traditional IndexedDB. It simplifies the API while still maintaining its structure. Here we are showing the enhancements only as to why we can use the Promised library to know more about it you can visit the following website − https://developers.google.com It has a few enhancements − IDBDatabase IDBTransaction IDBCursor IDBDatabase Shortcuts to get or set from an object store const value = await db.get(storeName, key); await db.put(storeName, value, key); Shortcuts to get from an Index const value = await db.getFromIndex(storeName, indexName, key); IDBTransaction tx.store If a transaction is a single store the store property references the store or else it is undefined then we use const tx = db.transaction(”any transaction”); const store = tx.store; tx.objectStore(storeName); tx.done The .done promise resolves when a transaction is completed successfully else it rejects with a transaction error. const tx = db.transaction(storeName, ”readwrite”); await Promise.all([ tx.store.add(”one”, ”two”), tx.store.put(”three”, ”four”), tx.done, ]); IDBCursor The cursor advance methods are − Advance Continue ContinuePrimaryKey They return a promise to cursor or else it returns null. let cursor = await db.transaction(storeName).store.openCursor(); while (cursor) { document.write(cursor.key, cursor.value); cursor = await cursor.continue(); } Print Page Previous Next Advertisements ”;
IndexedDB – Cursors
IndexedDB – Cursors ”; Previous Next In retrieving data we used the get() function when we knew what key we wanted to retrieve but if we want to step through all the values of the object store we can use cursors. Firstly we use the open cursor function and then we can add our arguments to it. The arguments which we can insert in openCursor() function are − Limit the range of objects by using a key range The direction in which we want to iterate Following is the syntax of cursors Syntax ObjectStore.openCursor(optionalKeyRange, optionalDirection); For the object store, we use the openCursor() optionalKeyRange − we can limit the range of how many objects we need to retrieve. optionalDirection − we can specify the direction we want to iterate. Example 1 In this example, we learn how to open a cursor function using JavaScript − var objectStore = db.transaction(“student”).objectStore(“student”); objectStore.openCursor().onsuccess = event => { var cursor = event.target.result; if (cursor) { document.write(“Name” + cursor.key + cursor.value.name); cursor.continue(); } else { document.write(“entries closed”); } }; Example 2 When we want to retrieve all objects from the object store and place them in an array. var student = []; objectStore.openCursor().onsuccess = event => { var cursor = event.target.result; if (cursor) { student.push(cursor.value); cursor.continue(); } else { document.write(student); } }; Example 3 Given below is another example to implement the openCursor() function in JavaScript − var singleKeyRange = IDBKeyRange.only(“Jason”); var lowerBoundKeyRange = IDBKeyRange.lowerBound(“Praneeth”); var lowerBoundOpenKeyRange = IDBKeyRange.lowerBound(“jason”, true); var upperBoundOpenKeyRange = IDBKeyRange.upperBound(“praneeth”, true); var boundKeyRange = IDBKeyRange.bound(“jason”, “praneeth”, false, true); index.openCursor(boundKeyRange).onsuccess = event => { var cursor = event.target.result; if (cursor) { cursor.continue(); } }; or else if we want to give the direction − objectStore.openCursor(boundKeyRange, “prev”).onsuccess = event => { var cursor = event.target.result; if (cursor) { cursor.continue(); } }; HTML Example The HTML script to implement the usage of cursor function is given as follows − <!DOCTYPE html> <html lang=”en”> <head> <title>Document</title> </head> <body> <script> const request = indexedDB.open(“botdatabase”,1); request.onupgradeneeded = function(){ const db = request.result; const store = db.createObjectStore(“bots”,{ keyPath: “id”}); store.createIndex(“branch_db”,[“branch”],{unique: false}); } request.onsuccess = function(){ document.write(“database opened successfully”); const db = request.result; const transaction=db.transaction(“bots”,”readwrite”); const store = transaction.objectStore(“bots”); const branchIndex = store.index(“branch_db”); store.add({id: 1, name: “jason”,branch: “IT”}); store.add({id: 2, name: “praneeth”,branch: “CSE”}); store.add({id: 3, name: “palli”,branch: “EEE”}); store.add({id: 4, name: “abdul”,branch: “IT”}); store.put({id: 4, name: “deevana”,branch: “CSE”}); const req = store.openCursor(); req.onsuccess = function(){ const cursor = req.result; if(cursor){ const key = cursor.key; const value = cursor.value; document.write(key,value); cursor.continue(); } else { document.write(“bots completed”); } } transaction.oncomplete = function(){ db.close; } } </script> </body> </html> Output database opened successfully 1 {id: 1, name: ”jason”, branch: ”IT”} 2 {id: 2, name: ”praneeth”, branch: ”CSE”} 3 {id: 3, name: ”palli”, branch: ”EEE”} 4 {id: 4, name: ”deevana”, branch: ”CSE”} bots completed Print Page Previous Next Advertisements ”;
IndexedDB – ECMAScript Binding ”; Previous Next Firstly, what is ECMAScript? ECMAScript (European Computer Manufacturers Association Script) is a scripting language based on JavaScript. JavaScript ES6 adds new syntaxes and features so that the code is more easily readable and we can write less code for the same functionality. ES6 has many new features like arrow functions, template strings, class destruction, etc. Binding – Bind an object to a function and reference it using the ‘this’ keyword. ECMAScript deals with keys, values, and keypaths. It defines how key values defined in this specification are converted to and from ECMAScript values. Extract a key from a value To extract a key from a value using a key path with value, keyPath, and an optional multi-entry flag we need to follow the following steps. The results can be a key, invalid, failure, or even an exception. Where r is the result of evaluating a keypath on a value with value and keypath. Rethrow any exceptions. If r is a failure return failure. key be the result of converting a value to a key with r if the multi-entry flag is false, and the result of converting a value to a multi-entry key with r otherwise. Rethrow any exceptions. If the key is invalid, return invalid. Return key. Print Page Previous Next Advertisements ”;
IndexedDB – Quick Guide
IndexedDB – Quick Guide ”; Previous Next IndexedDB – Introduction A database management system provides a mechanism for the storage and retrieval of data. There are various kinds of databases available mostly used ones among them are − Hierarchical databases Network databases Object-oriented databases Relational databases NoSQL databases NoSQL databases A NoSQL database (sometimes called Not Only SQL) is a database that provides a mechanism to store and retrieve data other than the tabular relations used in relational databases. These databases are schema-free, support easy replication, have simple API, are eventually consistent, and can handle huge amounts of data (big data). There are different types of NoSQL databases also like − Document databases. Key-value stores. Column-oriented databases. Graph databases. What is IndexedDB Indexed Database is a type of NoSQL database or Non−relational structured query language. It is a transactional database system, like an SQL−based RDBMS. However, unlike SQL−based RDBMSs, which use fixed-column tables, IndexedDB is a JavaScript−based object-oriented database. It is used when we need to store significant amounts of data on the server side and faster than local storage. Since it stores the data in the browser it can be used online and offline too. Using this, you can create a web application (with rich query abilities) that can run whether an internet connection is available or not. Key Characteristics of IndexedDB Following are the key characters of the IndexedDB database − IndexedDB is a NoSQL database that stores key−value pairs. It can store almost any kind of value by keys or multiple key types. As mentioned, IndexedDB follows a transactional database model − Transaction is a wrapper class around the operation or group of operations so that data integrity is maintained. You don”t want data to be altered or missed so if the transaction is failed a callback is rolled out. IndexedDB does not use Structured Query Language − Since IndexedDB uses a NoSQL database it doesn’t use SQL, instead, it uses queries on Indexes to produce data via cursors or the getAll() method to iterate around different sets. IndexedDB uses a lot of requests − Requests are objects that receive the success or failure of DOM events (DOM – HTML DOM events allow JavaScript to register different event handlers on elements in an HTML document). DOM events are success or error which has a target property that indicates the flow of the request. Success events can’t be canceled but, error events can be canceled. There are a lot of requests in IndexedDB like on success, onerror and addEventListener(), removeEventListener() on them. For getting to know the status of the request we also have ready state, result, and error code properties. IndexedDB needs to follow the same origin − Origin is the URL of the document in which the script is being written, each origin has some databases under it and each database has its name to be identified by the origin. The security boundary imposed on IndexedDB prevents applications from accessing data with a different origin. For example, if we take a URL and take different subdirectories of it, it can retrieve data but if we change location to port 8080 and try to retrieve data from the usual URL and the changed port, we cannot retrieve the data. Terminology Following are various important terms in indexedDB that you should know before proceeding further − Database − In IndexedDB database is the highest level which contains the object stores that contain the data. Object Stores − Object stores are the data storage entities of IndexedDB. Think of it as tables in RDBMS where we store data based on the type of data we want to store (ex: id, name, roll no, etc). Transaction − For any database operation we do the following process. Get database object Open transaction on the database Open object store on the transaction and then, operate on object store. So basically, a transaction is a wrapper function that is connected to every database and it ensures data integrity such that if the transaction is canceled or any error happens it will call back to where the transaction has not yet been begun. Index − Think of object store as a table and we use indexes to retrieve data of a single property from them. Ex: Name, age, etc. Cursor − In a database, if we need to traverse multiple records from object stores we use cursors. Support for IndexedDB IndexedDB is a database in a browser so, we need to check if it is supported by the current/existing browser. To do so, paste the following code in an text editor save it as test.html and run it your browser. const indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB || window.shimIndexedDB; if (!indexedDB) { document.write(“IndexedDB could not be found in this browser.”); } const request = indexedDB.open(“MyDatabase”, 1); If IndexedDB is supported by your browser this program gets executed successfully, an a database will be created. IndexedDB – Installation Visual Studio Code is a code editor redefined and optimized for building and debugging modern web and cloud applications. You can download the visual studio code from its official website – https://code.visualstudio.com Select the version you want based on your PC configuration and OS. Once downloaded you can install it directly on your computer. Installing the Visual Studio Code installer on Windows First of all download the Visual Studio Code installer for Windows as specified above − Once it is downloaded, run the installer. Then, accept the agreement and click on next. Now, click
IndexedDB – Searching
IndexedDB – Searching ”; Previous Next We encounter many situations where we need to search for values in an object store. Object stores are sorted internally. It can be done by − Searching by a key value or a key range. Searching based on another object field. Searching by Key We can search for exact key values or a range of key values by using IDBKeyRange objects with an acceptable key Range. IDBKeyRange object has the following calls − IDBKeyRange.lowerBound(lower, [open]) for >=lower IDBKeyRange.upperBound(upper, [open]) for >=upper IDBKeyRange.bound(lower, upper, [lowerOpen] , [upperOpen]) between lower and upper IDBKeyRange.only(key) if the range contains only one key. To perform the actual search we use the query argument on the object store. The different types of methods to perform these operations are store.get(query) − Search for the first value in the store by a key or a range store.getAll([query],[count]) − Search for all values in the store till the limit of the count mentioned. store.getKey(query) − search for the first key for which the query is satisfied. store.getAllKeys([query],[count]) − search for all the keys for which the query is satisfied till the limit of the count is completed. store.count([query]) − get the total count of the keys for which the query is satisfied. Example In this example, we are retrieving all the objects using the getAll() method and searching for objects by their key − class.get(‘student’) class.getAll(IDBKeyRange.bound(‘science’,’math’) class.getAll(IDBKeyRange.upperbound(‘science’,true) class.getAll() class.getAllKeys(IDBKeyRange.lowerbound(‘student’,true)) Searching by a field or index To search based on other object fields we need to use indexes. An index stores a list of keys for objects that have the value required. Indexes are also internally sorted like object stores. Syntax objectStore.createIndex(name, keyPath, [options]); name − Index Name keyPath − Searching will be done on the path to the object field options − options are of 2 types unique − Objects in the store with a unique value will be present at the key path and duplicates cannot be made of them. multi−entry − if the value on the keypath is an array then by default the index will treat the whole array as a key but if we use multi-entry the array members will become index keys. Example If we want to search for phones based on price, the example program is as follows − openRequest.onupgradeneeded = function() { let books = db.createObjectStore(”phone”, {keyPath: ”id”}); let index = books.createIndex(”pricephone”, ”price”); }; To create an index we need to use the upgrade needed. the index will track the price field. If the price is not unique we can”t set the unique option. If the price is not an array then multiEntry is not applicable. Example In the following example, we create a transaction and retrieve all the objects using the getAll() function. Once they are retrieved, we search for object values in that transaction. If found, return the object; if not, return false. let transaction = db.transaction(“phones”); let books = transaction.objectStore(“phones”); let priceIndex = books.index(“price_index”); let request = priceIndex.getAll(7); request.onsuccess = function() { if (request.result !== undefined) { document.write(“Phones”, request.result); } else { document.write(“There are no such phones”); } }; HTML Example The HTML script implementation to search for values in object store is given below − <!DOCTYPE html> <html lang=”en”> <head> <title>Document</title> </head> <body> <script> const request = indexedDB.open(“botdatabase”,1); request.onupgradeneeded = function(){ const db = request.result; const store = db.createObjectStore(“bots”,{ keyPath: “id”}); store.createIndex(“branch_db”,[“branch”],{unique: false}); } request.onsuccess = function(){ document.write(“database opened successfully”); const db = request.result; const transaction=db.transaction(“bots”,”readwrite”); const store = transaction.objectStore(“bots”); const branchIndex = store.index(“branch_db”); store.add({id: 1, name: “jason”,branch: “IT”}); store.add({id: 2, name: “praneeth”,branch: “CSE”}); store.add({id: 3, name: “palli”,branch: “EEE”}); store.add({id: 4, name: “abdul”,branch: “IT”}); store.put({id: 4, name: “deevana”,branch: “CSE”}); const req = branchIndex.getAll([“CSE”]); req.onsuccess = function(){ if(req.result!==undefined){ document.write(“bots”,req.result); } else{ document.write(“There are no such bots”); } }; transaction.oncomplete = function(){ db.close; } } </script> </body> </html> Output database opened successfully bots (2) [{…}, {…}] arg1:(2) [{…}, {…}] 0:{id: 2, name: ”praneeth”, branch: ”CSE”} 1:{id: 4, name: ”deevana”, branch: ”CSE”} length:2 [[Prototype]]:Array(0) [[Prototype]]:Object Print Page Previous Next Advertisements ”;
Using getAll() Functions
IndexedDB – Using getAll() Function ”; Previous Next In the previous sections, we only retrieved objects from the store one at a time. Now we can retrieve all the data or subsets of the object stores. The get all method returns all the objects in the object store using the getAll() function Syntax ObjectStore.getAll(optionalConstraint); We can directly call getAll() to return all the objects stored in the object store or else we can specify an optional constraint for example red colored cars from a car database Example In the following example script, we are calling the getAll() method to return all the objects stored in the object store at once − <!DOCTYPE html> <html lang=”en”> <head> <title>Document</title> </head> <body> <script> const request = indexedDB.open(“botdatabase”,1); request.onupgradeneeded = function(){ const db = request.result; const store = db.createObjectStore(“bots”,{ keyPath: “id”}); store.createIndex(“branch_db”,[“branch”],{unique: false}); } request.onsuccess = function(){ document.write(“database opened successfully”); const db = request.result; const transaction=db.transaction(“bots”,”readwrite”); const store = transaction.objectStore(“bots”); const branchIndex = store.index(“branch_db”); store.add({id: 1, name: “jason”,branch: “IT”}); store.add({id: 2, name: “praneeth”,branch: “CSE”}); store.add({id: 3, name: “palli”,branch: “EEE”}); store.add({id: 4, name: “abdul”,branch: “IT”}); store.put({id: 4, name: “deevana”,branch: “CSE”}); const query = branchIndex.getAll([“IT”]); query.onsuccess = function(){ document.write(“query”,query.result); } transaction.oncomplete = function(){ db.close; } } </script> </body> </html> Output database opened successfully query (1) [{…}] arg1:(1) [{…}] 0:{id: 1, name: ”jason”, branch: ”IT”} length:1 [[Prototype]]:Array(0) [[Prototype]]:Object Print Page Previous Next Advertisements ”;