Friday, November 25, 2011

Indexed DB: Reading data

Finally we get to the part where we can see the results of our Indexed DB tutorial. For the last few moths we have been structuring our database, adding data and now I’ll show how you can read data from an Indexed DB. For this we have 2 approaches. First one is retrieving a single record and the other way is retrieving a collection of records by a cursor.

In this post I’ll handle the retrieving of a single record. A post about retrieving data with a cursor will appear in the near future.

Retrieving data from an object store

In the IObjectStore interface we have an get method to retrieve data. This method must be provided with a key we want to search on. The key parameter can be a valid key or a key range. In case you don’t provide a valid key, a DATA_ERR exception will be thrown.

In the first situation a record of the object store will be retrieved where the given key is the same as the key of the key/value pair. In the other situation, the first record will be retrieved that matches one of the keys defined in the key range. If no record gets found, the result will be undefined. If you are using the Indexed DB prototype on IE 9, you’ll get an “Object with specified key not found.” error in stead of an result.

Time for some code:

When we want to read data, we need to create a transaction. This we do on the same way as for adding data. The only difference is we can use the IDBTransaction.READ_ONLY mode. This is the type that will be used as default when we create a transaction.

   1: var txn = dbconnection.transaction([“ObjectStoreName”]);
   2: var objectStore = txn.objectStore(“ObjectStoreName”);

The result of the get method is a IDBrequest object. When this is successful, the record is added to the result.



   1: var getReq = store.get(key);
   2: getReq.onsuccess = function(event) { 
   3:     var result;
   4:     // IE 9 implementation
   5:     if(event.result){
   6:         result = event.result;
   7:     }
   8:     // IE 10, Chrome and Firefox implementation
   9:     else if (getReq.result){
  10:         result = getReq.result;
  11:     }
  12:     // Code to present the result on your screen
  13: };

Retrieving data from an Index


In a previous post I have been talking about Indexes. Indexes make it possible to look up data from the object store by fields of the value object. By example: we have an object store person. In this object store we store persons. A person object has a first name and a last name field. By creating an index with a key path “last name”, we make it possible to retrieve data from the object store by providing the last name of the person.


In the IDBIndex interface we have the get method to retrieve a record from the object store, and the GetKey method to retrieve the key of the record from the object store. In both cases a key must be provided. This key parameter can be a valid key or a key range. For the rest every thing works the same as for retrieving data from an object store.


One think you need to keep in mind. In the Indexed DB prototype on IE9 the get and getKey method work different. In this case the getKey method retrieves the data and the get method the key of the record.



   1: var txn = dbconnection.transaction([“ObjectStoreName”]);
   2: var objectStore = txn.objectStore(“ObjectStoreName”);
   3: var index = store.index(“IndexName”);
   4: var getReq = index.getKey(key);
   5:  
   6: getReq.onsuccess = function(event) { 
   7:     var result;
   8:     if(event.result){
   9:         result = event.result;
  10:     }
  11:     else{
  12:         result = getReq.result
  13:     }
  14:     // Code to present the result on your screen
  15: };

Wednesday, November 9, 2011

Indexed DB: Manipulating data

The first thing we need to do when we want to read data, is to make sure we have data available in our database. So this post will handle inserting and updating data into the database.

For inserting data we have 2 possibilities: we have an add and a put method available. Both methods take the same parameters, but there is a slight difference between them. When we use the add method, we need to be sure that no other object with the same key is already added in the database. If it does, an constraint error (CONSTRAINT_ERR) will occur. So the add method will only be used when we want to add data that won’t be overwritten when it is already present with the same key in the database.

The put method we will usually use when we want to update data. If the data isn’t present yet with the same key, the data will be inserted. If you want some more information about the steps for storing a record into an object store, you can find this here on the W3C specs site.

Make sure when you are starting a new transaction to manipulate data, you will use a read_write transaction. Otherwise you will receive an READ_ONLY_ERR when calling the methods.

The put and the add method are both available in the IObjectStore interface. This means once we have created the transaction where we will work in, we need to retrieve the object store we want to work on. We do this by calling the ObjectStore method on the transaction. The only thing we need to pass is the name of the object store.
var txn = dbconnection.transaction([“ObjectStoreName”]
                                                 , IDBTransaction.READ_WRITE);
var objectStore = txn.objectStore(“ObjectStoreName”);
Once we have the object store object, we can start adding data to it. The result of the add operation is an IDBRequest object. This means the onsuccess will be called when the operation was successful and an onerror will be called when something went wrong.
When the onsuccess function gets called, the result of this action will be the key of the object in the object store
var addresult = objectStore.add(data);
addresult.onsuccess = function (event) {
      // Adding data is successful
      // Commit the transaction when using IE9
      var key;

      // IE 9 implementation
      if(event.result){
            key = event.result
      }
      // IE 10, Chrome and Firefox implementation
      else if (addresult.result){
            key = addresult.result;
      }
};
addresult.onerror = function (event) {
      // Handle the error
}
If we use a put for adding or changing data, we get the same structure only we will use the put method instead.
var putresult = objectStore.put(data);
putresult.onsuccess = function (event) {
      // Putting data is successful
      // Commit the transaction when using IE9
};
putresult.onerror = function (event) {
      // Handle the error
}
Now that we have added some data to our database, we can start retrieving it and present it to our users…

Thursday, November 3, 2011

Indexed DB: Deleting your database

In a previous post I have been talking about creating and deleting a database. The creation/opening of a database is supported in all the major browsers, but deleting isn’t. Only Internet Explorer currently supports deleting your database trough the IDBFactory interface.

Because we have been playing for a while now, it’s interesting we can delete our database so we can rebuild it from scratch without having to use a new name for our database. I’m only used to work on windows machines, so the solution I will propose will probably only work under windows. If you are using an other operating system, it will work on the same way, but you’ll have to look where you can find the databases.

Firefox

The Indexed DB databases of Firefox can be found on the following location:

<location of the windows user profiles>\<account name>\AppData\Roaming\
Mozilla\Firefox\Profiles\<some random characters>.default\IndexedDB

In my case this is:

C:\Users\kristof\AppData\Roaming\Mozilla\Firefox\Profiles\ tvv6t475.default\indexedDB

You will find a folder with your current domain. Delete these folder, and you can start all over again. In my case, I get the following:

http+++localhost+50350

I have to notice that the AppData folder is a hidden folder, so it is possible you won’t see it when going to your user profile directory.

Chrome

The Indexed DB databases of Chrome can be found on the following location:

<location of the windows user profiles>\<account name>\AppData\Local\Google\
Chrome\User Data\Default\IndexedDB

In my case this is:

C:\Users\kristof\AppData\Local\Google\Chrome\User Data\Default\IndexedDB

You will find a folder and a file with your current domain. Delete these files, and you can start all over again.

In my case I get the following:

folder: http_localhost_50350.indexeddb.leveldb
file:     http_localhost_50350.indexeddb

Wednesday, November 2, 2011

Indexed DB: Transactions

Today, I’ll handle the transaction subject. As said in previous posts, every request made to the database needs to be done in a transaction. So for every read or write request we need to create a new transaction. There for we need a database connection and 2 argument that we will pass to the transaction method.

The first argument will define the scope of the transaction. Here we pass all the object stores we want to use during the transaction. We do this by passing the object store names in an array. Providing an empty array will allow to use all available object stores in the database.

The second argument is the mode we want to use to access the data. This is an optional parameter and if not provided the transaction will be created read only by default. If you want to manipulate data, you’ll need to pass IDBTransaction.READ_WRITE. There is also a third mode, CHANGE_VERSION, but this type of transaction can only be created in the setVersion method. More about this method can be found in my post about Indexed DB: Defining the database structure

var txn = dbconnection.transaction([], IDBTransaction.READ_WRITE);

txn.oncomplete = function () {
     // Transaction successful
};
txn.onabort = function () {
    // Code to handle the abort of the transaction
};
txn.onerror = function () {
// Code to handle the error
};

For a transaction we have 3 possible outcomes. The first one is that the transaction is committed and so got completed. This function will be called if the transaction was successful and in the case we were reading data, we can here write the code to show the retrieved data it in the browser. Keep in mind that a transaction in the Indexed DB API is committed by default, but in IE9 you still need to do this manually.

The onabort function will be called when we manually call the abort function on the transaction object. This means the transaction must do a rollback.

The last one will handle all the errors that can occur within the transaction, this will also mean that the transaction must rollback.

Now that we know how to create a transaction, we can start retrieving and manipulating data from our database. This will be the next subject of my future posts.