Among the concepts used by IndexedDB is the concept of transactions.
A transactional database ensures that concurrent access to data would not compromise this data.
It uses a locking system, that means that when an instance of your Web application is modifying some data and another instance or another application on the same domain is reading this data, there won't be anything wrong regarding to this data.
So when do we need such a mechanism? When you have multiple tabs opened on the same WebApp or WebApps from the same domain.
Or you have got multiple games that store high scores and they are all coming from the"MyBeautifulGame.com" domain.
They will share the same database so you need to have some security system.
But remember also that HTML5 is also used for writing applications that run outside of the traditional browser, like on a game console… the PS4, the Xbox One... your Windows desktop uses also applications written in HTML5.
All these applications will belong to the same default domain and if they need to store data, in an IndexedDB database -there is an IndexedDB database in your Xbox or in your PlayStation-!
Then, in that case all these applications will have to fight for accessing the data and you need transactions.
Another concept is called the KeyPath.
The KeyPath is like a unique ID attached to each data in your database.
And this KeyPath is either one explicit property, in that case the social security number, it's a unique ID attached to each data in your data store and it is called the KeyPath, it should be unique.
It can be explicit or implicit, if you do not specify any KeyPath when you create your database another extra property will be added to your object.
It's a bit like the auto-incremented primary keys in the SQL world.
You can also have flexible schemas for your data.
All your data need to share the unique ID I just talked about, but they can have some variable properties... you can have some contacts for example, in your data store, that have one single phone number or multiple phone numbers, or a description, or an age, or a name attached to them… … but not all objects must share the same schema like what you have got in relational tables in a relational databases.
Another concept we find in most databases is the concept of ‘indexes’.
You can specify that a property of your object you store in a database is an index.
In that case, the retrieval of data using this index will be much faster.
And indexes, contrarily to KeyPath, can be unique or non unique.
For example if my object has a lastName, I can have several objects with lastName being Buffa, my family name, and I can send a request to the database asking for all the people whose lastName is equal to Buffa.
And in that case, the retrieval will be much faster than if lastName was not an index.
So to sum up: IndexedDB is a NoSQL database, that stores JavaScript objects.
It runs in your browser (client side), it uses transactions - so several tabs or several applications on the same domain can access with a lot of security a same data at the same time.
It uses indexes for faster retrieval, and finally it can hold huge amount of data.
So thanks for your attention, in the next videos we will look at some pieces of code to learn how to program some application that will use IndexedDB.
Bye bye!
IndexedDB is very different from SQL databases, but don't be afraid if you've only used SQL databases: IndexedDB might seem complex at first sight, but it really isn't.
Let's quickly look at the main concepts of IndexedDB, as we will go into detail later on:
IndexedDB stores and retrieves objects which are indexed by a "key".
Changes to the database happen within transactions.
IndexedDB follows a same-origin policy. So while you can access stored data within a domain, you cannot access data across different domains.
It makes extensive use of an asynchronous API: most processing will be done in callback functions - and we mean LOTS of callback functions!
IndexedDB databases store key-value pairs. The values can be complex structured objects (hint: think in terms of JSON objects), and keys can be properties of those objects. You can create indexes that use any property of the objects for faster searching, as well as ordering results.
Example of data (we reuse a sample from this MDN tutorial: "Using IndexedDB)":
// This is what our customer data looks like.
const customerData = [
{ ssn: "444-44-4444", name: "Bill", age: 35, email: "bill@company.com" },
{ ssn: "555-55-5555", name: "Donna", age: 32, email: "donna@home.org" }
];
Where customerData is an array of "customers", each customer having several properties: ssn for the social security number, a name, an age and an email address.
IndexedDB is built on a transactional database model. Everything you do in IndexedDB happens in the context of a transaction. The IndexedDB API provides lots of objects that represent indexes, tables, cursors, and so on, but each is tied to a particular transaction. Thus, you cannot execute commands or open cursors outside a transaction.
Example of a transaction:
// Open a transaction for reading and writing on the DB "customer"
var transaction = db.transaction(["customers"], "readwrite");
// Do something when all the data is added to the database.
transaction.oncomplete = function(event) {
alert("All done!");
};
transaction.onerror = function(event) {
// Don't forget to handle errors!
};
// Use the transaction to add data...
var objectStore = transaction.objectStore("customers");
for (var i in customerData) {
var request = objectStore.add(customerData[i]);
request.onsuccess = function(event) {
// event.target.result == customerData[i].ssn
};
}
Transactions have a well-defined lifetime. Attempting to use a transaction after it has completed throws an exception.
Transactions auto-commit, and cannot be committed manually.
This transaction model is really useful when you consider what might happen if a user opened two instances of your web app in two different tabs simultaneously. Without transactional operations, the two instances might stomp all over each others' modifications.
The IndexedDB API is mostly asynchronous. The API doesn't give you data by returning values; instead, you have to pass a callback function. You don't "store" a value in the database, or "retrieve" a value out of the database through synchronous means. Instead, you "request" that a database operation happens. You are notified by a DOM event when the operation finishes, and the type of event lets you know if the operation succeeded or failed. This may sound a little complicated at first, but there are some sanity measures baked-in. After all, you are a JavaScript programmer, aren't you? ;-)
So, please review the previous code extracts noting: transaction. oncomplete, transaction. onerror, request. onsuccess, etc.
IndexedDB uses requests all over the place. Requests are objects that receive the success or failure DOM events mentioned previously. They have onsuccess and onerror properties, and you can call addEventListener() and removeEventListener() on them. They also have readyState, result, and errorCode properties which advise the status of a request.
The result property is particularly magical, as it can be many different things, depending on how the request was generated (for example, an IDBCursor instance, or the key for a value that you just inserted into the database). We will see this in detail during a future lecture: "Using IndexedDB".
IndexedDB uses DOM events to notify you when results are available. DOM events always have a type property (in IndexedDB, it is most commonly set to "success" or "error"). DOM events also have a target property that shows where the event is headed. In most cases, the target of an event is the IDBRequest object that was generated as a result of doing some database operation. Success events don't bubble up and they can't be cancelled. Error events, on the other hand, do bubble, and can be cancelled. This is quite important, as error events abort the transaction, unless they are cancelled.
IndexedDB is object-oriented. IndexedDB is not a relational database, which has tables with collections of rows and columns. This important and fundamental difference affects the way you design and build your applications. IndexedDB is an Object Store!
In a traditional relational data store, you would have a table that stores a collection of rows of data and columns of named types of data. IndexedDB, on the other hand, requires you to create an object store for a type of data and simply persist JavaScript objects to that store. Each object store can have a collection of indexes (corresponding to the properties of the JavaScript object you store in the store) that enable efficient querying and iteration.
IndexedDB does not use Structured Query Language (SQL). It phrases a query in terms of an index, that produces a cursor, which you use to iterate through the result set. If you are not familiar with NoSQL systems, read the Wikipedia article on NoSQL.
IndexedDB adheres to a same-origin policy. An origin consists of the domain, the application layer protocol, and the port of a URL of the document where the script is being executed. Each origin has its own associated set of databases. Every database has a name that identifies it within an origin. Think of it as: "an application + a Database".
The concept of "same origin" is defined by the combination of all three components mentioned earlier (domain, protocol, port). For example, an app in a page with the URL https://www.example.com/app/, and a second app at https://www.example.com/dir/, may both access the same IndexedDB database because they have the same origin (https, example.com, and 80). Whereas apps at https://www.example.com:8080/dir/ (different port) or https://www.example.com/dir/ (different protocol), do not satisfy the same origin criteria (port or protocol differ from https://www.example.com)
See this article from MDN about the same-origin policy for further details and examples.