KEMBAR78
IndexedDB - Querying and Performance | PPTX
Prepare yourselves




The Mobile has arrived
Go where no website has gone before
Scotty, beam me up




I have good internet bandwidth
Darth Vader Says
Work when you are disconnected too
What if I told you




that adding Offline support is easy ?
A simple website
                   DATA in
                   SERVER




                    DATA in
                   BROWSER
SHOW ME
http://nparashuram.com/conference
Simple Read Operation
AjaxHandler = {
    getSession: function (id) {
        // code goes here
    },
    getAllSessions: function () {
        // code goes here
    }
}


  var Session = Backbone.Model.extend({});
  var SessionList = Backbone.Collection.extend({});

  var singleSession = new Session();
  singleSession.get(101);
  view.update(singleSession);

  var allSessions = new SessionList();
  allSessions.fetch();
  view.render(allSessions);
Backbone.sync = function (method, model, options, error)
{
    switch (method) {
        case "read":
            // Methods for reading from database
            break;
        case "create":
           // Create a record here
            break;
        case "update":
           // Update Records
            break;
        case "delete":
          // Delete record
    }
RemoteDatabase.replicate();
});
case "read":// Pseudo Code
if (model.id) {// for a single Model
    db.get(model.id,
        function (err, res) {
         if (err) {
             error(err);
             return;
         }
         options.success(res);
        }
    );
} else {    // For all rows in the DB
    db.getAll (
       function (err, resp) {
         if (err) {
             error(err);
             return;
         }
         options.success(resp);
       }
    );
}
With all that pseudo code




 I totally understand you
case "read": // Real IndexedDB Code
if (model.id) {// for a single Model
    var openReq = window.indexedDB.open("DatabaseName");
    openReq.onsuccess = function () {
        var db = openReq.result;
        var transaction = db.transaction(["Model1”], "readonly");
        var objectStore = transaction.objectStore("Model1");
        var readReq = objectStore.get(model.id);
        readReq.onsuccess = function () {
            option.success(readReq.result);
        };
    };
    openReq.onerror = function (e) {
        options.error(e);
    };
}
What did you just do ?
IndexedDB Refresher
     http://yourwebpage.com                                               search



               Database                               Database
  Transaction
  Object Store                             Object Store

   key : value                 Index        key : value           Index
   key : value                              key : value
                              Cursor on                          Cursor on
   key : value                  Index       key : value            Index

 Cursor on Object                         Cursor on Object
      Store                                    Store
case "read":

if (model.id) {
    var openReq = window.indexedDB.open("DatabaseName");
    openReq.onsuccess = function () {
        var db = openReq.result;
        var transaction = db.transaction(["Model1”], "readonly");
        var objectStore = transaction.objectStore("Model1");
        var readReq = objectStore.get(model.id);
        readReq.onsuccess = function () {
            option.success(readReq.result);
        };
    };
    openReq.onerror = function (e) {
        options.error(e);
    };
}
You wrote so much code




Just to read a single record ?
case "read": // Jquery-IndexedDB Plugin

if (model.id) {
    var openReq = window.indexedDB.open("DatabaseName");
    $.indexedDB("DatabaseName")
    openReq.onsuccess = function () {
        var db = openReq.result;
        var transaction = db.transaction(["Model1”], "readonly");
        var objectStore = transaction.objectStore("Model1");
       .objectStore("Model1")
       .get(model.id) objectStore.get(model.id);
        var readReq =
        readReq.onsuccess = function () {
       .done(function(data) {
            option.success(readReq.result);
        };
       })
        readReq.onerror = function (e) {
       .fail(function (error) {
             options.error(e);
        };
       });
    };
    openReq.onerror = function (e) {
        options.error(e);
    };
}
case "read": // Jquery-IndexedDB Plugin
$.indexedDB("DatabaseName")
    .objectStore("Model1")
    .get(model.id)                     •   Less Verbose
    .done(function (data) {
        option.success(data);          •   Chainable API
    }).fail(function (error) {
        option.error(error);
                                       •   Use Promises
    });                                •   Smart Defaults
                                       •   Almost transparent
$.indexedDB("DatabaseName")
    .objectStore("Model1")
    .each(function (record) {
        display(record);
    }).done(function () {
        // Finished with all records
                                       Project :
    }).fail(function () {              gitbhub
        // Error
    });                                /axemclion
                                       /jquery-indexeddb
case "read":// Pouch DB Code
 if (model.id) {// for a single Model
     db.get(model.id, {},
         function (err, res) {
          if (err) {
              error(err);
              return;
          }
          options.success(res);
         }
     );
 } else {    // For all rows in the DB
     db.allDocs ({},
        function (err, resp) {
          if (err) {
              error(err);
              return;
          }
          options.success(resp);
        }
     );
Pouch.replicate("idb://data","http://me.couchdb.com/data");
 }
Sure, but can you query data ?
Querying IndexedDB

        $.indexedDB("DatabaseName")
            .objectStore("Model1")
            .where('price < 100')
            .sortBy('price')
            .desc()




         objectStore.index('price').openCursor(
             IDBKeyRange.lowerBound(100, false),
             "prev"
         );
Querying IndexedDB

        $.indexedDB("DatabaseName")
            .objectStore("Model1")
            .where('price < 100 and >= 200')
            .sortBy('price')
            .desc()


        objectStore.index('price').openCursor(
            IDBKeyRange.bound(100, 200, false, true),
            "prev"
        );
Querying IndexedDB
var results = $.indexedDB("DatabaseName")
                  .objectStore("Model1")
                  .where('price < 100 and >= 200')
                  .sortBy('name')
                  .desc()
                  .done(function(results){
                      // do something with results
                      // results.length == ???
                  })
         objectStore.index('price').openCursor(
             IDBKeyRange.bound(100, 200, false, true),
             "prev"
         );
Querying IndexedDB
                  $.indexedDB("DatabaseName")
                        .objectStore("Model1")
                        .where('price < 100 and >= 200')
                        .where('ratings > 4')
                        .sortBy('name')
                        .desc()
                        .each(function(result){
                       .done(function(results){
                                 process each result
                             // do something with results
                        }) // results.length == ???
cursorReq =              })
            objectStore.index('name').openCursor();
cursorReq.onsuccess = function () {
    if (cursorReq.result) {
        val = cursorReq.result.value;
        if (val.price < 100 && val.price > 200 && val.ratings > 4)
                                               )
           callback(val);
        cursorReq.result.continue();
    }
}
Querying IndexedDB
          $.indexedDB("DatabaseName")
              .objectStore("Model1")
              .where('price < 100 and >= 200')
              .where(‘Model2.empId < 5')
              .sortBy('name')
              .sortBy('price')
              .each(function(result){
                  // process each result
              });
Querying IndexedDB
                       $.indexedDB("DatabaseName")
                           .objectStore("Model1")
                           .where('price < 100 and >= 200')
                           .where(‘Model2.empId < 5 ')
                           .sortBy('name')
                           .sortBy('price')
                           .each(function(result){
                               // process each result
                           });
 Fall back on Web Workers to do the job

 • Sorting on multiple columns
 • Where clauses across object stores
 • Sorting and clauses across object stores



        Project : //linq2indexeddb.codeplex.com/
ONE DOES NOT SIMPLY START USING INDEXEDDB




    WITHOUT LOOKING AT PERFORMANCE
Comparing IndexedDB and WebSQL ?
Performance Analysis
• Common cases when writing an application
   • Are string keys slower than integer keys
   • Should I combine read and write transactions ?
• Started with JSPerf, Problems with Async Setup
   • Using Benchmarkjs




  Thanks to @slace for helping with code reviews
http://nparashuram.com/IndexedDB/perf
May the force be with you
     http://nparashuram.com
    @nparashuram

           Resources
   @OpenAtMicrosoft
      (@obloch)
http://nparashuram.com/IndexedDB
    http://www.html5labs.com/

IndexedDB - Querying and Performance

  • 3.
  • 4.
    Go where nowebsite has gone before
  • 6.
    Scotty, beam meup I have good internet bandwidth
  • 7.
    Darth Vader Says Workwhen you are disconnected too
  • 8.
    What if Itold you that adding Offline support is easy ?
  • 9.
    A simple website DATA in SERVER DATA in BROWSER
  • 10.
  • 11.
  • 12.
    Simple Read Operation AjaxHandler= { getSession: function (id) { // code goes here }, getAllSessions: function () { // code goes here } } var Session = Backbone.Model.extend({}); var SessionList = Backbone.Collection.extend({}); var singleSession = new Session(); singleSession.get(101); view.update(singleSession); var allSessions = new SessionList(); allSessions.fetch(); view.render(allSessions);
  • 13.
    Backbone.sync = function(method, model, options, error) { switch (method) { case "read": // Methods for reading from database break; case "create": // Create a record here break; case "update": // Update Records break; case "delete": // Delete record } RemoteDatabase.replicate(); });
  • 14.
    case "read":// PseudoCode if (model.id) {// for a single Model db.get(model.id, function (err, res) { if (err) { error(err); return; } options.success(res); } ); } else { // For all rows in the DB db.getAll ( function (err, resp) { if (err) { error(err); return; } options.success(resp); } ); }
  • 15.
    With all thatpseudo code I totally understand you
  • 16.
    case "read": //Real IndexedDB Code if (model.id) {// for a single Model var openReq = window.indexedDB.open("DatabaseName"); openReq.onsuccess = function () { var db = openReq.result; var transaction = db.transaction(["Model1”], "readonly"); var objectStore = transaction.objectStore("Model1"); var readReq = objectStore.get(model.id); readReq.onsuccess = function () { option.success(readReq.result); }; }; openReq.onerror = function (e) { options.error(e); }; }
  • 17.
    What did youjust do ?
  • 18.
    IndexedDB Refresher http://yourwebpage.com search Database Database Transaction Object Store Object Store key : value Index key : value Index key : value key : value Cursor on Cursor on key : value Index key : value Index Cursor on Object Cursor on Object Store Store
  • 19.
    case "read": if (model.id){ var openReq = window.indexedDB.open("DatabaseName"); openReq.onsuccess = function () { var db = openReq.result; var transaction = db.transaction(["Model1”], "readonly"); var objectStore = transaction.objectStore("Model1"); var readReq = objectStore.get(model.id); readReq.onsuccess = function () { option.success(readReq.result); }; }; openReq.onerror = function (e) { options.error(e); }; }
  • 20.
    You wrote somuch code Just to read a single record ?
  • 21.
    case "read": //Jquery-IndexedDB Plugin if (model.id) { var openReq = window.indexedDB.open("DatabaseName"); $.indexedDB("DatabaseName") openReq.onsuccess = function () { var db = openReq.result; var transaction = db.transaction(["Model1”], "readonly"); var objectStore = transaction.objectStore("Model1"); .objectStore("Model1") .get(model.id) objectStore.get(model.id); var readReq = readReq.onsuccess = function () { .done(function(data) { option.success(readReq.result); }; }) readReq.onerror = function (e) { .fail(function (error) { options.error(e); }; }); }; openReq.onerror = function (e) { options.error(e); }; }
  • 22.
    case "read": //Jquery-IndexedDB Plugin $.indexedDB("DatabaseName") .objectStore("Model1") .get(model.id) • Less Verbose .done(function (data) { option.success(data); • Chainable API }).fail(function (error) { option.error(error); • Use Promises }); • Smart Defaults • Almost transparent $.indexedDB("DatabaseName") .objectStore("Model1") .each(function (record) { display(record); }).done(function () { // Finished with all records Project : }).fail(function () { gitbhub // Error }); /axemclion /jquery-indexeddb
  • 23.
    case "read":// PouchDB Code if (model.id) {// for a single Model db.get(model.id, {}, function (err, res) { if (err) { error(err); return; } options.success(res); } ); } else { // For all rows in the DB db.allDocs ({}, function (err, resp) { if (err) { error(err); return; } options.success(resp); } ); Pouch.replicate("idb://data","http://me.couchdb.com/data"); }
  • 24.
    Sure, but canyou query data ?
  • 25.
    Querying IndexedDB $.indexedDB("DatabaseName") .objectStore("Model1") .where('price < 100') .sortBy('price') .desc() objectStore.index('price').openCursor( IDBKeyRange.lowerBound(100, false), "prev" );
  • 26.
    Querying IndexedDB $.indexedDB("DatabaseName") .objectStore("Model1") .where('price < 100 and >= 200') .sortBy('price') .desc() objectStore.index('price').openCursor( IDBKeyRange.bound(100, 200, false, true), "prev" );
  • 27.
    Querying IndexedDB var results= $.indexedDB("DatabaseName") .objectStore("Model1") .where('price < 100 and >= 200') .sortBy('name') .desc() .done(function(results){ // do something with results // results.length == ??? }) objectStore.index('price').openCursor( IDBKeyRange.bound(100, 200, false, true), "prev" );
  • 28.
    Querying IndexedDB $.indexedDB("DatabaseName") .objectStore("Model1") .where('price < 100 and >= 200') .where('ratings > 4') .sortBy('name') .desc() .each(function(result){ .done(function(results){ process each result // do something with results }) // results.length == ??? cursorReq = }) objectStore.index('name').openCursor(); cursorReq.onsuccess = function () { if (cursorReq.result) { val = cursorReq.result.value; if (val.price < 100 && val.price > 200 && val.ratings > 4) ) callback(val); cursorReq.result.continue(); } }
  • 29.
    Querying IndexedDB $.indexedDB("DatabaseName") .objectStore("Model1") .where('price < 100 and >= 200') .where(‘Model2.empId < 5') .sortBy('name') .sortBy('price') .each(function(result){ // process each result });
  • 31.
    Querying IndexedDB $.indexedDB("DatabaseName") .objectStore("Model1") .where('price < 100 and >= 200') .where(‘Model2.empId < 5 ') .sortBy('name') .sortBy('price') .each(function(result){ // process each result }); Fall back on Web Workers to do the job • Sorting on multiple columns • Where clauses across object stores • Sorting and clauses across object stores Project : //linq2indexeddb.codeplex.com/
  • 32.
    ONE DOES NOTSIMPLY START USING INDEXEDDB WITHOUT LOOKING AT PERFORMANCE
  • 33.
  • 35.
    Performance Analysis • Commoncases when writing an application • Are string keys slower than integer keys • Should I combine read and write transactions ? • Started with JSPerf, Problems with Async Setup • Using Benchmarkjs Thanks to @slace for helping with code reviews
  • 36.
  • 37.
    May the forcebe with you http://nparashuram.com @nparashuram Resources @OpenAtMicrosoft (@obloch) http://nparashuram.com/IndexedDB http://www.html5labs.com/