Web developers already have localStorage, which is used for client side storage of simple key-value pairs. This alone doesn’t address the needs of many web applications for structured storage and indexed data. Mozilla is working on a structured storage API with indexing support called IndexedDB, and we will have some test builds in the next few weeks. This can be compared to the WebDatabase API implemented by several browsers that uses a subset of the allowable language of SQLite. Mozilla has chosen to not implement WebDatabase for various reasons discussed in this post.

In order to compare IndexedDB and WebDatabase, we are going to show four examples that use most parts of the asynchronous APIs of each specification. The differences between SQL storage with tables (WebDatabase) and JavaScript object storage with indexes (IndexedDB) becomes pretty clear after reading the examples. The synchronous versions of these APIs are only available on worker threads. Since not all browsers currently implement worker threads, the synchronous APIs will not be discussed at this time. The IndexedDB code is based off a proposal that Mozilla has submitted to the W3C WebApps working group that has gotten positive feedback so far. The code for both APIs does not include any error handling (for brevity), but production code should always have it!

These examples are for the storage of a candy store’s sale of candy to customers, which we’ll refer to as kids. Each entry in candySales represents a sale of a specified amount of candy to a kid, specified by an entry in candy and kids respectively.

Example 1 – Opening and Setting Up a Database

This first example demonstrates how to open a database connection and create the tables or object stores if the version number is not correct. Upon opening the database, both examples check the version and create the necessary tables or object stores and then set the correct version number. WebDatabase is a bit stricter in how it handles versions by giving an error if the database version is not what the caller expects (this is specified by the second argument to openDatabase). IndexedDB simply lets the caller handle versioning as they see fit. Note that there is active discussion about how IndexedDB should handle version changes in the working group.

WebDatabase

var db = window.openDatabase("CandyDB", "",
                             "My candy store database",
                             1024);
if (db.version != "1") {
  db.changeVersion(db.version, "1", function(tx) {
    // User's first visit.  Initialize database.
    var tables = [
      { name: "kids", columns: ["id INTEGER PRIMARY KEY",
                                "name TEXT"]},
      { name: "candy", columns: ["id INTEGER PRIMARY KEY",
                                 "name TEXT"]},
      { name: "candySales", columns: ["kidId INTEGER",
                                      "candyId INTEGER",
                                      "date TEXT"]}
    ];
 
    for (var index = 0; index < tables.length; index++) {
      var table = tables[index];
      tx.executeSql("CREATE TABLE " + table.name + "(" +
                    table.columns.join(", ") + ");");
    }
  }, null, function() { loadData(db); });
}
else {
  // User has been here before, no initialization required.
  loadData(db);
}

IndexedDB

var request = window.indexedDB.open("CandyDB",
                                    "My candy store database");
request.onsuccess = function(event) {
  var db = event.result;
  if (db.version != "1") {
    // User's first visit, initialize database.
    var createdObjectStoreCount = 0;
    var objectStores = [
      { name: "kids", keyPath: "id", autoIncrement: true },
      { name: "candy", keyPath: "id", autoIncrement: true },
      { name: "candySales", keyPath: "", autoIncrement: true }
    ];
 
    function objectStoreCreated(event) {
      if (++createdObjectStoreCount == objectStores.length) {
        db.setVersion("1").onsuccess = function(event) {
          loadData(db);
        };
      }
    }
 
    for (var index = 0; index < objectStores.length; index++) {
      var params = objectStores[index];
      request = db.createObjectStore(params.name, params.keyPath,
                                     params.autoIncrement);
      request.onsuccess = objectStoreCreated;
    }
  }
  else {
    // User has been here before, no initialization required.
    loadData(db);
  }
};

Example 2 – Storing Kids in the Database

This example stores several kids into the appropriate table or object store. This example demonstrates one of the risks that have to be dealt with when using WebDatabase: SQL injection attacks. In WebDatabase explicit transactions must be used, but in IndexedDB a transaction is provided automatically if only one object store is accessed. Transaction locking is per-object store in IndexedDB. Additionally, IndexedDB takes a JavaScript object to insert, whereas with WebDatabase callers must bind specific columns. In both cases you get the insertion id in the callback.

WebDatabase

var kids = [
  { name: "Anna" },
  { name: "Betty" },
  { name: "Christine" }
];
 
var db = window.openDatabase("CandyDB", "1",
                             "My candy store database",
                             1024);
db.transaction(function(tx) {
  for (var index = 0; index < kids.length; index++) {
    var kid = kids[index];
    tx.executeSql("INSERT INTO kids (name) VALUES (:name);", [kid],
                  function(tx, results) {
      document.getElementById("display").textContent =
          "Saved record for " + kid.name +
          " with id " + results.insertId;
    });
  }
});

IndexedDB

var kids = [
  { name: "Anna" },
  { name: "Betty" },
  { name: "Christine" }
];
 
var request = window.indexedDB.open("CandyDB",
                                    "My candy store database");
request.onsuccess = function(event) {
  var objectStore = event.result.objectStore("kids");
  for (var index = 0; index < kids.length; index++) {
    var kid = kids[index];
    objectStore.add(kid).onsuccess = function(event) {
      document.getElementById("display").textContent =
        "Saved record for " + kid.name + " with id " + event.result;
    };
  }
};

Example 3 – List All Kids

This example lists all of the kids stored in the kids table or the kids object store. WebDatabase uses a result set object which will be passed to the callback method provided after all rows have been retrieved. IndexedDB, on the other hand, passes a cursor to the event handler as results are retrieved. Results should come back faster, as a result. While not shown in this example, you can also stop iterating data with IndexedDB by simply not calling cursor.continue().

WebDatabase

var db = window.openDatabase("CandyDB", "1",
                             "My candy store database",
                             1024);
db.readTransaction(function(tx) {
  // Enumerate the entire table.
  tx.executeSql("SELECT * FROM kids", function(tx, results) {
    var rows = results.rows;
    for (var index = 0; index < rows.length; index++) {
      var item = rows.item(index);
      var element = document.createElement("div");
      element.textContent = item.name;
      document.getElementById("kidList").appendChild(element);
    }
  });
});

IndexedDB

var request = window.indexedDB.open("CandyDB",
                                    "My candy store database");
request.onsuccess = function(event) {
  // Enumerate the entire object store.
  request = event.result.objectStore("kids").openCursor();
  request.onsuccess = function(event) {
    var cursor = event.result;
    // If cursor is null then we've completed the enumeration.
    if (!cursor) {
      return;
    }
    var element = document.createElement("div");
    element.textContent = cursor.value.name;
    document.getElementById("kidList").appendChild(element);
    cursor.continue();
  };
};

Example 4 – List Kids Who Bought Candy

This example lists all the kids, and how much candy each kid purchased. WebDatabase simply uses a LEFT JOIN query which makes this example very simple. IndexedDB does not currently have an API specified for doing a join between different object stores. As a result, the example opens a cursor to the kids object store and an object cursor on the kidId index on the candySales object store and performs the join manually.

WebDatabase

var db = window.openDatabase("CandyDB", "1",
                             "My candy store database",
                             1024);
db.readTransaction(function(tx) {
  tx.executeSql("SELECT name, COUNT(candySales.kidId) " +
                "FROM kids " +
                "LEFT JOIN candySales " +
                "ON kids.id = candySales.kidId " +
                "GROUP BY kids.id;",
                function(tx, results) {
    var display = document.getElementById("purchaseList");
    var rows = results.rows;
    for (var index = 0; index < rows.length; index++) {
      var item = rows.item(index);
      display.textContent += ", " + item.name + "bought " +
                             item.count + "pieces";
    }
  });
});

IndexedDB

candyEaters = [];
function displayCandyEaters(event) {
  var display = document.getElementById("purchaseList");
  for (var i in candyEaters) {
    display.textContent += ", " + candyEaters[i].name + "bought " +
                           candyEaters[i].count + "pieces";
  }
};
 
var request = window.indexedDB.open("CandyDB",
                                    "My candy store database");
request.onsuccess = function(event) {
  var db = event.result;
  var transaction = db.transaction(["kids", "candySales"]);
  transaction.oncomplete = displayCandyEaters;
 
  var kidCursor;
  var saleCursor;
  var salesLoaded = false;
  var count;
 
  var kidsStore = transaction.objectStore("kids");
  kidsStore.openCursor().onsuccess = function(event) {
    kidCursor = event.result;
    count = 0;
    attemptWalk();
  }
  var salesStore = transaction.objectStore("candySales");
  var kidIndex = salesStore.index("kidId");
  kidIndex.openObjectCursor().onsuccess = function(event) {
    saleCursor = event.result;
    salesLoaded = true;
    attemptWalk();
  }
  function attemptWalk() {
    if (!kidCursor || !salesLoaded)
      return;
 
    if (saleCursor && kidCursor.value.id == saleCursor.kidId) {
      count++;
      saleCursor.continue();
    }
    else {
      candyEaters.push({ name: kidCursor.value.name, count: count });
      kidCursor.continue();
    }
  }
}

IndexedDB generally simplifies the programming model for interacting with databases, and allows for a wide number of use cases. The working group is designing this API so it could be wrapped by JavaScript libraries; for instance, there’s plenty of room for a CouchDB-style API on top of our IndexedDB implementation. It would also be very possible to build a SQL-based API on top of IndexedDB (such as WebDatabase). Mozilla is eager to get developer feedback about IndexedDB, particularly since the specification has not been finalized yet. Feel free to leave a comment here expressing your thoughts or leave anonymous feedback through Rypple.

170 comments

Post a comment
  1. HurfDurf wrote on June 1st, 2010 at 12:30 pm:

    Are you also going to add an option to disable this “feature”?

    More types of stealth cookies aren’t exactly wanted by anyone.

    Reply

    1. Shawn Wilsher wrote on June 1st, 2010 at 1:25 pm:

      You can disable it the same way you can disable sessionStorage or localStorage.

      Reply

      1. Andy wrote on June 1st, 2010 at 2:35 pm:

        > More types of stealth cookies aren’t exactly wanted by anyone.

        Have you ever heard of offline-capable webapps? That’s what IndexedDB is mainly for.

        A friendly suggestion: *Think*, before you post.

        Reply

        1. Shawn Wilsher wrote on June 1st, 2010 at 8:13 pm:

          Lets keep it civil please.

          Reply

          1. Ege wrote on August 26th, 2010 at 7:18 am:

            Keeping it civil is something but most people are sick of these over-paranoid responses these days. You expect someone to respect the content and ask meaningful questions. That one is not a good example. You explain a technology and the first commenter asks about how to disable it… How can we keep it civilized? I totally agree with Andy. You have to “think” before you say something. Like you do it when talking face-to-face.

  2. Pingback from Beyond HTML5: Database APIs and the Road to IndexedDB ✩ Mozilla Hacks – the Web developer blog on June 1st, 2010 at 1:24 pm:

    [...] Newer Article [...]

    Reply

  3. Jesper Kristensen wrote on June 1st, 2010 at 1:44 pm:

    That example code is seriously ugly.

    Not only are Mozilla internal APIs like the new Add-ons manager API almost unusable, but now it has also infected open standards.

    Browser vendors really needs to move JavaScript forward and provide a sane way of writing asynchronous JavaScript.

    Reply

    1. Preston L. Bannister wrote on June 2nd, 2010 at 1:51 pm:

      Agreed. As an example of JavaScript usage, and an API to use from JS, this is some seriously ugly code.

      Reply

  4. Wes Brown wrote on June 1st, 2010 at 2:00 pm:

    You had me until the JOIN example… that’s a nightmare. Until there is some reasonable API for multi-table access no one is going to want to go through all that error-prone rigmarole just to do a simple join.

    Reply

    1. Shawn Wilsher wrote on June 1st, 2010 at 2:19 pm:

      Right, joins aren’t so pleasant with the current API proposal. However, IndexedDB is more of a document store and not , and if you map object stores to tables, like we did in this example, you will end up having to worry about joins. If you think about this more like a CouchDB style database things get much simpler to use.

      Reply

      1. voracity wrote on June 2nd, 2010 at 7:29 am:

        If you don’t provide a simple join function in the base API, you run the risk of nobody trying to grapple with the IndexedDB way of thinking for long enough to bother writing a simpler API over the top that contains what we actually want: i.e. joins!

        A simple join function should be very easy to do, so why not just do it? Nested objects are great —awesome in fact — but they probably don’t cover even half of the cases in which people want to use joins; joins are more like cross-referencing documents rather than subsections in a document. (And that couchdb joins article shows just how illegible things can get.)

        I think the overall approach and reasoning is good. Just join it with joins.

        Reply

    2. Tom Harrison wrote on August 19th, 2010 at 12:24 pm:

      I was skeptical, but OK until the join example, as you say.

      IndexDB is just a hash, which is conceptually simple, fast and all, but is useful only in very limited cases as a mechanism for storing and retrieving structured data. It’s fine for handling serialized objects.

      A significant case for real storage is for mobile apps that should be able to work in the absence of a connection. It makes sense to have a subset of your server-based database stored locally and then synced at the next connection.

      I am no fan of SQL (I have watched so-called developers abuse it for years), but it is a well-developed standard that solves a lot of problems that hashed databases don’t. The absence of a standard is a laughable reason to abandon the approach, and it’s classic bloat mentality that suggests we built yet another SQL engine on top of the IndexDB storage engine. SQLite is fine.

      Sorry, I am venting.

      Reply

      1. Artifex wrote on December 1st, 2010 at 2:34 pm:

        I have to agree that the code for IndexedDB, is far less attractive to me than the Web Database code. I’m a web developer, and insulated from most SQL work, so I would think that a methodology like IndexedDB would be more attractive to me, as it’s more familiar, but I have to go with the standard SQL query language here. I’m no DB admin, but that SQL code looks a lot more inviting.

        Reply

  5. George Moschovitis wrote on June 1st, 2010 at 2:40 pm:

    Interesting idiom for async JavaScript.

    BTW, can you use multiple indices in a single ‘query’ ?
    is it possible to do >, < queries?

    Reply

    1. Shawn Wilsher wrote on June 1st, 2010 at 2:53 pm:

      I think that the current proposal does not allow multiple indexes per query. It does support closed ranges (which is what I think you are asking for with “> , <" with the IDBKeyRange interface:

      interface IDBKeyRange {
        const unsigned short SINGLE = 0;
        const unsigned short LEFT_OPEN = 1;
        const unsigned short RIGHT_OPEN = 2;
        const unsigned short LEFT_BOUND = 4;
        const unsigned short RIGHT_BOUND = 8;
       
        readonly attribute any left;
        readonly attribute any right;
        readonly attribute unsigned short flags;
      };

      Reply

  6. John wrote on June 1st, 2010 at 3:26 pm:

    I think what you lose in javascripty-ness with the SQL examples you gain in readability. I have to work hard to understand what you are doing in the IndexedDB examples (because although it may be more native to JavaScript, it’s new to us). Pretty much everyone knows SQL, so reading that is simple.

    Also, just a question because it really bothers me, isn’t there a race condition when you say:

    var request = window.indexedDB.open(“CandyDB”,
    “My candy store database”);

    and then on the next line define the onsuccess handler? Now, that may never be a problem, but isn’t that happening?

    Reply

    1. Shawn Wilsher wrote on June 1st, 2010 at 4:26 pm:

      For your first point, I’m going to direct you to Arun’s post where he talks about why we didn’t go with SQL.

      There is no race condition there because JavaScript will always run to completion. That is, your entire function will run before any callbacks or event handlers can possibly begin. We wouldn’t even try to dispatch success until your function has completed.

      Reply

  7. Laurens Holst wrote on June 1st, 2010 at 3:27 pm:

    I’d suggest RDF as a superior, well-defined graph-oriented data modelling technology if it wouldn’t be dismissed right away.

    Reply

    1. goldfrapper wrote on June 2nd, 2010 at 1:19 am:

      Mozilla used to use rdf. A proper/interfaceable RDF implementation would indeed be better considering the resourcefull nature of webapplications. Or they could ofcourse go for a couchdb-like model

      Reply

      1. Shawn Wilsher wrote on June 2nd, 2010 at 9:55 am:

        IndexedDB is very much like a CouchDB model. CouchDB will also be implementable on top of it (we are working with the couchio guys to make sure it will).

        Reply

  8. Screwtape wrote on June 1st, 2010 at 4:55 pm:

    It saddens me to see Yet Another Asynchronous API that isn’t composable with all the other asynchronous APIs available to JS in a webpage (such as XmlHttpRequest, Web Workers, setTimeout and so forth). The best asynchronous-result model I’ve ever seen is Twisted Python’s “Deferred” class, neatly ported to JavaScript as part of the MochiKit framework:

    http://www.mochikit.com/doc/html/MochiKit/Async.html#fn-deferred

    See DeferredLock and DeferredList in that same API for useful functionality that can be easily composed with any other asynchronous request that uses Deferreds.

    Reply

    1. Shawn Wilsher wrote on June 1st, 2010 at 5:01 pm:

      How, exactly, is it not composable with XMLHttpRequest? We are interested in feedback, but it isn’t clear to me why it is not composable seeing as how it is the same event model as XMLHttpReqeust.

      Reply

      1. Screwtape wrote on June 1st, 2010 at 7:54 pm:

        By “composable” I don’t just mean “can be made to work with”, I mean “naturally slots in alongside”. XMLHttpRequest and IndexedDB both use an “event model”, but they use different events (“onreadystatechange” versus “onsuccess” and “onerror”).

        How about this: imagine I have some code that currently retrieves various kinds of data with XMLHttpRequest, and I want to update it so that it first checks an IndexedDB cache before sending a request. If I want to implement this cache without changing all the code that calls it, my new code has to do all the IndexedDB stuff, then return an object that fakes the (somewhat complicated) XMLHttpRequest API.

        Using Deferreds, that shim function might look something like this:

        function getDataShim(key) {
            var d = getDataFromDB(key);
         
            function cacheAndPassthrough(result) {
        	d = cacheValueInDB(result);
        	d.addCallback(function (ignored) { return result; });
        	return d;
            }
         
            function notFoundInDB(failure) {
        	var d = getDataFromWeb(key);
         
        	d.addCallback(cacheAndPassthrough);
         
        	return d;
            }
         
            d.addErrback(notFoundInDB);
         
            return d;
        }

        Roughly translated, this says “Try to get the data from the database. If it’s there, it’s the result. If an error is encountered (such as ‘not found’), try to get the data from the web. If we get the data from the web succeeds, cache the found value in the DB and return that data. If we fail to get the data from the web, or fail to cache the data, return that error.

        I’ll be the first to admit that Deferreds don’t make for the most clean and readable code, but asynchronous functions in a procedural langugage are never going to be clean and tidy – and Deferreds are far better than every asynchronous function having its own way of returning results and signalling errors.

        Reply

        1. Shawn Wilsher wrote on June 1st, 2010 at 8:18 pm:

          I’m not sure I completely agree with you about asynchronous APIs and procedural languages. Generators go a long way to making the code very readable as demonstrated here.

          There’s also another spec in the W3C right now (I think it is something like programmable cache) that accomplishes a lot of what you are talking about.

          Reply

          1. Screwtape wrote on June 1st, 2010 at 10:41 pm:

            You’re right, that Generator-based code does make the asynchronous nature look a lot flatter – I suspect it would get a bit uglier if your Generator-based asynchronous function wanted to call other Generator-based asynchronous functions, though.

            Twisted has a few methods for integrating Python’s generators (which are very like the JS generators you talk about) with its Deferred system:

            http://blog.mekk.waw.pl/archives/14-Twisted-inlineCallbacks-and-deferredGenerator.html

            I’m not specifically interested in a caching system, that was just the first example I thought of that combined multiple, different asynchronous events.

          2. ged wrote on October 21st, 2010 at 12:32 pm:

            its this i believe:

            http://www.w3.org/TR/DataCache/

  9. Music Teacher wrote on June 1st, 2010 at 4:59 pm:

    This is interesting stuff! And yeah, while the JOIN stuff may be a little unwieldy I have to say I’m really glad you’re avoiding using SQL database fu.

    Reply

  10. Jonas Sicking wrote on June 1st, 2010 at 6:48 pm:

    For what it’s worth, I agree with those that clamor a better way of doing asynchronous coding in JavaScript. There are several proposals out there, beside the already mentioned “Deferred” class in Twisted Python, Dojo has a similar Deferred module, and recent versions of Firefox has an experimental shallow continuations implementation, (see https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Iterators_and_Generators).

    I would love to see the various asynchronous DOM APIs out there grow native support for one of these features. However trying to specify which model to use as part of a database specification would be a mistake. This could lead to disastrous results such as having XMLHttpRequest using one Defer solution, and IndexedDB using another.

    I’d love to see a solution for asynchronous API developed for the web. We could then add support for that in loads of specifications, such as IndexedDB, WebWorkers, XMLHttpRequest, WebSocket, etc. However until we have such a standardized solution, I think it’s best to stick with the model that exists, namely DOM Events. That way libraries such as dojo.Deferred have a consistent API to work against to bridge the gap until we have something better.

    As for joins. It was a tough call weather to include them or not in our examples. Proper use of IndexedDB would really be to put both the list of kids and the sales into one table. I.e. have objects like:

    { name: "Anna", sales: [
      { date: "5-1-2010", candyType: "lollipop" },
      { date: "5-13-2010", candyType: "swedish fish"}]
    }

    This completely removes the need for the join and makes things very easy.

    You can still create an index which contains just the sales in case you need to do queries that way.

    So really, object stores together with custom indexes removes much of the need for joins. The reason we still included them in our example was that we wanted to show an example of a complex query in order to spark imagination.

    Reply

  11. David wrote on June 1st, 2010 at 6:53 pm:

    I’m glad you’re pushing for IndexedDB. Even though it looks harder to use from the onset, that’s where frameworks come in. The ability to have a low level API that you can use to build a user friendly database API (be i SQL based or whatever) makes a lot more sense than starting with a user fiendly API that gives you little flexibility.

    BTW, the email address validator is rejecting legit email addresses. (i.e. user+something@example.com doesn’t work)

    Reply

    1. Shawn Wilsher wrote on June 1st, 2010 at 8:26 pm:

      That’s really what the working group is shooting for too. We are trying to create a low-level API that is powerful so that libraries can do some amazing things with it. It’s worked pretty well with the web so far, and the really good APIs have then been standardized and made faster by the browser vendors.

      Reply

    2. Tom Harrison wrote on August 19th, 2010 at 12:36 pm:

      It sounds like what’s happening is that IndexedDB is creating a storage engine and punting on a well-established, highly functional, approach for managing the data.

      The reason people hate SQL is that it addresses a fundamentally very hard problem, in particular enforcing data integrity. And having spent many years cleaning up bad data, I know that it’s a hard problem. Many databases get it wrong, some very wrong. SQL is hard, but in a certain way it’s still an elegant solution to a very hard problem. As I understand, this is not a problem that IndexedDB addresses, and that would be a serious loss.

      Reply

  12. Mark Rendle wrote on June 2nd, 2010 at 1:44 am:

    “IndexedDB generally simplifies the programming model for interacting with databases”

    It plainly doesn’t. The programming model for interacting with databases has JOINs. And maybe the sync model is better, but that async Javascript looks awful.

    Reply

  13. alex wrote on June 2nd, 2010 at 10:05 pm:

    The golden rule for a spec: simple things should be simple, complex things – possible.

    In indexedDB even simplest things are horrendously complex. I agree that SQL syntax maybe should not be used in webapps, however it *should* be a better way to define queries in pure JS without writing hundred lines of code to do simple joins.

    My verdict: IndexedDB is not ready for *any* production use at the moment.

    Reply

  14. 29a wrote on June 3rd, 2010 at 8:37 am:

    It looks better than webdb to me. The api seems to be a bit verbose, but it should be easy to build something like mongoose could be built on top of it: http://www.learnboost.com/mongoose/.

    Jonas

    Reply

  15. Darren wrote on June 4th, 2010 at 11:00 am:

    Shawn,
    There is a race condition in your code as the gentleman pointed out. You open the indexDB in one statment and then attempt to add a callback handler in the next statement. If the first call completes and the database open completes before the onsuccess handler is added, then the handler is never called.

    If, on the other hand, the database open call does not complete before the onsuccess handler is invoked, then why not? The correct way is for the callback to be added at the same time the method is invoked so internally, the handler is added BEFORE the attempt to open the database occurs.

    Please correct this! :)

    Darren

    Reply

    1. Shawn Wilsher wrote on June 7th, 2010 at 10:16 am:

      There isn’t actually a race condition in this code, as I indicated here. JavaScript is single threaded, so your asynchronous callback is not going to happen until your current code is finished executing. I’d be happy to go into more detail if needed here, but this is pretty trivial for implementers to ensure consumers don’t race.

      We would race if you add the event listeners in a setTimeout FWIW.

      Reply

      1. Darren Govoni wrote on June 7th, 2010 at 10:33 am:

        I’m not convinced and I think for other peoples comfort you should explain in more detail. But I will explain why I think there is a race condition.

        1:        var request = window.indexedDB.open("CandyDB",
                                            "My candy store database");
        2:        request.onsuccess = function(event) {
         
                   };

        In the above code (single threaded), statement 1 completes before statement 2 begins. Correct? When statement 1 completes, it can be true that the database is thus open. Typically, all the registered listeners are notified BEFORE statement 1 would complete and this is how a race condition can be avoided. Ergo, it is deterministic.

        Line 2, however, now attempts to add a listener. What code, then, will be notifying the listener in line 2 of the open event, and whatever code does that, resides outside the completion scope of line 1. yes?

        Reply

        1. Shawn Wilsher wrote on June 7th, 2010 at 10:42 am:

          I think you are making the assumption that openDatabase is synchronous, but it is in fact asynchronous. No events will be dispatched until some time after openDatabase returns. I’m going to do a new post handling some of the more commonly asked questions with detailed answers where I’ll provide a much more detailed response.

          Reply

  16. Mewp wrote on June 4th, 2010 at 1:46 pm:

    Looks like a question whether we prefer CouchDB-like databases, or SQL-like ones.

    The autor of the artice argues that we could implement both on top of IndexedDB, but that’s also true for any other database API. We could as well implement IndexedDB on top of WebDatabase. We could probably implement WebDatabase on top of local storage, so what?

    Those implementations will be slower than a native mechanism, so in my opinion, browsers should implement the faster and more flexbible one.

    About substituting joins with proper database structure — there are situations in which joins will still be necessary. For example, an app may have a timetable, or some kind of a calendar. And we want to check, whether there any two events at the same time occuring.

    In SQL: SELECT 1 FROM Timetable t1 JOIN Timetable t2 ON t1.time = t2.time LIMIT 1

    In IndexedDB (just guessing, correct me if I’m wrong):
    var rows = [];
    var t1 = transaction.objectStore(‘Timetable’);
    t1.openCursor().onsuccess = function(e) {
    var c1 = c.result;
    var t2 = transaction.objectStore(‘Timetable’);
    t2.onsuccess = function(e) {
    var c2 = c.result;
    if(c1.time == c2.time) {
    rows.push(1);
    // Now how do we end the computation here, since we have found that there are such events?
    }
    }
    c1.continue();
    }

    Even disregarding code complexity — which one will be faster, if implemented natively? My guess is SQL.

    Reply

    1. Shawn Wilsher wrote on June 7th, 2010 at 10:27 am:

      IndexedDB is essentially just exposing a B-tree API. CouchDB and SQL-based databases are all implemented on top of a B-tree. IndexedDB is really the lowest common denominator. The group working on the spec is designing this to be simple enough that people can use it without a library, but fully expect libraries to spring up and solve lots of pain points of a raw B-tree API.

      As for performance, your argument doesn’t really apply. Disk I/O is going to be far slower than JavaScript parsing the data. Even then, JavaScript engines in modern browsers are not exactly slow anymore.

      Reply

  17. Martin wrote on June 7th, 2010 at 3:52 am:

    I’m a bit surprised that in example 4 someone thinks IndexedDB simplifies live.
    The SQL approach is simple and clear.
    And in most cases, the SQL exists anyway.

    Reply

    1. Shawn Wilsher wrote on June 7th, 2010 at 10:32 am:

      I’m just going to quote what I originally wrote here…

      WebDatabase simply uses a LEFT JOIN query which makes this example very simple. IndexedDB does not currently have an API specified for doing a join between different object stores.

      Reply

  18. Darren Govoni wrote on June 7th, 2010 at 11:26 am:

    “I think you are making the assumption that openDatabase is synchronous, but it is in fact asynchronous.”

    Shawn, this is why its a race condition. Maybe in your tests that amount of time to open the database consistently happens AFTER the result.onsuccess registration, but you cannot expect that behavior uniformly. Its nondeterministic, from a computational perspective.

    To make it computationally reliable and deterministic, the handlers have to be registered prior to the open call or an exception should be thrown. Gambling that one call _should_ finish before a separate, asynchronous call is invoked leads to problems, IMO. Just my $0.02.

    Reply

    1. Rob Arnold wrote on June 7th, 2010 at 12:03 pm:

      “Its nondeterministic, from a computational perspective.”

      It’s true that opening the database is actually nondeterministic but the notification that it was opened is deterministic. The notification must be dispatched on the main thread per spec; this is the thread that the code creating the request is running on. Since JavaScript has run-to-completion semantics as Shawn mentioned earlier, the notification cannot be dispatched until the JS code that made the request is finished – this includes statement 2 and any future statements until control flow is returned to event loop. So in your annotated example, the notification could not possibly be dispatched before statement 2, even if the database was actually opened before then. Make sense?

      Reply

  19. austin wrote on June 10th, 2010 at 9:24 am:

    you are still not getting what he is saying, the call to open the database is not done UNTIL the script exits. so if i sat there calculating the sum primes from 1 to a billion between those two statements, we still wouldnt have a problem, because until im done doing my calculations, the call to open the database has NOT happened. once its done, database is called, and the notifications sent.

    Reply

  20. Darren Govoni wrote on June 11th, 2010 at 4:53 am:

    So if I step through the code with FireBug, all the code in the database open call will complete and not block. yes? then the function completes in the main thread. yes? Ok, then what code that issues the notifies? Your are saying the execution now goes back to some previous code to complete? I don’t think so.

    Where is that code? Back in the database open method? So then you are saying after the database open method, there are NO side effects? that’s complete nonsense from a programming point of view. But I will just wait for the code and step through it myself.

    Reply

    1. Rob Arnold wrote on June 11th, 2010 at 10:33 am:

      “So if I step through the code with FireBug, all the code in the database open call will complete and not block. yes?”

      Yes.

      “then the function completes in the main thread. yes?”

      Yes. But note that the function does not complete by opening the database. It completes by queuing the execution of a synchronous open in a separate thread context and returns.

      “Ok, then what code that issues the notifies?”

      When the aforementioned synchronous open finishes on a separate thread, it queues some code to run in the main thread’s event loop. That code will run call onsuccess.

      “Your are saying the execution now goes back to some previous code to complete? I don’t think so.”

      Well I’m not sure why you think open() doesn’t return like a normal function. It returns alright but there’s no guarantee the database has been opened when it does. If the database is opened by the time it returns (or at any point after it queues the synchronous open), then there’s an event waiting in the main thread’s event queue to dispatch the notification. That event doesn’t get run until the current thread of JS execution finishes. This is what is meant by “run to completion” semantics.

      “So then you are saying after the database open method, there are NO side effects?”

      From the script point of view, no, not until it yields control back to its original caller or otherwise invokes the event loop.

      From the browser’s point of view, there is of course a side effect – spawning the new thread of execution to open the DB.

      Reply

  21. Brett Zamir wrote on June 17th, 2010 at 7:55 pm:

    I would love to see a native XML database using XQuery made accessible to websites (and potentially shareable across applications).

    I just cannot understand why XQuery has not been embraced more widely except by some die-hard fans like myself, outside of venturing that it is because there is a lack of accessibility in common and accessible development environments like JavaScript or PHP.

    It is such an elegant and expressive language, and to me fits in with the web model more than any other.

    The examples above show the IndexDB as longer than the SQLite one. If the contrived examples are longer, that does not seem like a good sign, though I’ll admit I haven’t studied it carefully. But it doesn’t grab me as ultra-friendly like XQuery is.

    Shouldn’t the web leverage existing understanding of X/HTML on which the most basic unit of the web is built (as XQuery so conveniently allows targeted inclusion of XML in the input and output–similar to how E4X does, though which unfortunately hasn’t been given attention in other browsers) and is also based on other already convenient, standard, and familiar technologies (as XQuery leverages XPath)?

    Shouldn’t this new API work equally well for hierarchical data, as most web documents are?

    Shouldn’t data table creators be able to use simple XHTML to build an XHTML table and have it both be directly viewable and editable as a document in its own right as well as queryable easily through XPath/XQuery?

    If you want to work with tables, let people create the tables they’re most familiar with, . And for those who want to be able to work conveniently with hierarchical data (which might include for that matter) including via direct queries to a document or document collection, let us work with that…

    I have no idea how well it stacks up, but there is already a very small XML database (Apache license), Sedna: http://modis.ispras.ru/sedna/ which might be usable as a base.

    Reply

    1. Steve Antal wrote on June 17th, 2010 at 8:42 pm:

      XHTML is dead/deprecated, and in my opinion we need popular standards, that most people understand, there is already too much stuff a web developer needs to learn.

      This is why we need SQL, we need to minimize the amount of required knowledge.

      For example, XUL may be better for expressing UIs than HTML, but the fact that it’s required for created simple Firefox extensions is awkward. I don’t want to learn a zillion new technologies, my clients don’t pay me for technologies, they pay me for features.
      It is nice to create a simple browser-extension for a site, but in this scenario I don’t want to learn a new language just to be able to do it.

      My example may be hard to understand, but here is a simplified version(not directly related to this comment):
      Stop inventing new technologies!!! We don’t want new technologies, we want stuff that actually work.

      Reply

  22. Brett Zamir wrote on June 17th, 2010 at 7:58 pm:

    My second to last paragraph was supposed to have the table tag, but it was stripped due to overzealous comments: <table>

    Reply

  23. Brett Zamir wrote on June 17th, 2010 at 9:03 pm:

    At risk of distracting from my suggestion just now to simplify, I might add that there are XQuery-style interfaces to RDF as well (e.g., http://www.w3.org/2004/07/16-FA/ , http://www.fatdog.com/xsrql.html ), as might appeal to those who would go through the trouble of generating highly structured data (e.g., see http://dbpedia.org/ ), though I’m only suggesting this as a possible supplement to the far simpler XQuery+XML, not a replacement.

    In response to the comment just now, XHTML is not dead, as HTML5 is itself allowing an XHTML serialization. If you know HTML, it will take you about 5 minutes to learn how to write XHTML: http://www.w3schools.com/xhtml/xhtml_html.asp . And it’s not inconceivable that an XQuery-based XML database could be made to work against HTML (especially now that the rules for parsing HTML are being spelled out explicitly in HTML5).

    I did this with my add-on XqUSEme which uses Firefox’s own internal representation of HTML (which is usually close enough to XML) : https://addons.mozilla.org/en-US/firefox/addon/5515 , as apparently also does the interesting project XQIB in using Tidy: http://www.xqib.org/ ). But neither of these currently work with XML databases (only individual documents).

    As far as the query language, SQL is more familiar (if not exactly standard), that is true, and if I had my way, I’d even advocate allowing it. But SQL is not set up to work with hierarchical data, while XML+XQuery can do either. In my view, SQL’s success is an accident of history, while if XQuery (on which the SQL co-creator himself worked) had been the first out of the gate, it would have taken over. I hope the next generation will have access to its intuitiveness and power, especially in combination with Full Text and Update functionality included.

    Here are a few interesting use cases for XQuery against the Wikipedia database (using the very interest looking Sedna XML database I mentioned): http://wikixmldb.org/help/use-cases

    Reply

  24. Andrzej Lis wrote on June 21st, 2010 at 11:34 am:

    Its easy to understand developers that can’t imagine nothing more than tables. But Web is a graph over data organized hierarchical (domains n documents), I don’t see any tables there. I welcome storage more adequate for semi-structural information. My question then, taking excellent example of native XML database http://exist-db.org, how easy will be to implement some XML indexing scheme ( http://atomic.exist-db.org/articles/wolfgangs_talk.pdf ) for IndexedDB?

    Reply

  25. Andrzej Lis wrote on June 22nd, 2010 at 9:51 am:

    It’s easy to understand developers that can imagine just tables. But web is a graph over information organized hierarchical (domains n documents). I welcome storage more adequate for semi-structured nature of web data.
    My question is, taking excellent example of native XML database http://exist-db.org :

    how easy will be to implement some XML indexing scheme for IndexedDB ?

    (to know about relations without searching, but just by comparing node identifiers, what is useful for stuff like XQuery etc., http://atomic.exist-db.org/articles/wolfgangs_talk.pdf ).

    Reply

  26. Brett Zamir wrote on June 23rd, 2010 at 3:30 am:

    I’m not familiar with XQuery Update Facility, so I’ll stick to XQuery, but here’s a possible equivalent of the SELECT statement (in fewer lines and more functional friendly):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    var db = window.openDb("CandyDB", "My candy store database");
    db.readTransaction(function(tx) {
      // Enumerate all the rows.
      tx.executeXQueryForEach(
        'for $row in collection("kids")//tr'+
          'return {$row/td[@class="name"]/string()}',
        function (div) {
          document.getElementById("kidList").appendChild(div);
        }
      );
    });

    Or if we adapted a library like jQuery to accept XPath (as should be reasonable to convert CSS Selectors to the more powerful XPath) and handle collection() and doc() as used in XQuery, we might use the same API as above to simplify to:

    1
    2
    3
    4
    5
    6
    
    db.readTransaction(function(tx) {
      // Enumerate all the rows.
      $('collection("kids") tr'.each(function (row) {
        $('#kidList').append(''+$(this).find('td[class="name"]').text()+');
      });
    });

    Or wrapping even the transaction perhaps:

    1
    2
    3
    
    $('db("CandyDB", "My Candy Store Database") collection("kids") tr'.each(function (row) {
      $('#kidList').append(''+$(this).find('td[class="name"]').text()+');
    });

    And if for some reason you prefer the relational model to something as easy as this, just use something like this: http://github.com/nkallen/jquery-database

    Note that the above isn’t even demonstrating the ability to deal with hierarchical structures as it can with the same flexibility, unlike the relational model:

    1
    2
    3
    4
    
    $('db("Classics", "Classic Literature Database") '+
      'collection("ShakespeareWorks") .irony'.each(function (ironicPassage) {
      $('#TheBardOnIrony').append(ironicPassage);
    });

    Reply

  27. Brett Zamir wrote on June 23rd, 2010 at 3:41 am:

    (Ironic how I appended the passages as being about irony, when such classes would probably represent Shakespeare instead merely being ironic, but anyways)

    I know you could wrap the other types, but am I the only one who finds it so appealing to be able to work with data in such a way?

    Reply

  28. Evan Ireland wrote on June 27th, 2010 at 2:24 pm:

    I have two comments on the IndexedDB API.

    (1) It appears that you can have only one (primary key) index per table. As a result, many operations in a non-simple application will have to do table scans, and ordering/paging will be an issue. For example (for ordering/paging), suppose each company has zero or more employees. I want to write a query to display employees (ordered by last name, then first name) and for each employee, to display the employee name and company name. And in fact I want only from row M to N of that ordered result (to do paging). Now without an index on employee for lastname,firstname it seems unlikely to be possible to express this in any efficient way.

    (2) I really think we need a synchronous database API. I like that with the Web SQL Database API, there are both synchronous and asynchronous APIs available. My concern with the lack of a synchronous API is that composition becomes a nightmare. Suppose I have a class Employee, I would like to be able to generate code so the user can write:

    var e = … // get Employee from some query
    e.setPhone(\555 123-45567\);
    e.update();
    … // do something after the update

    If the generated Employee class has to use an asynchronous database API, then we cannot encapsulate the database access inside a synchronous \update\ method. Now if \update\ could take an unbounded amount of time, or for queries that may take a lot of time to execute (especially if there are insufficient indexes), I appreciate that an asynchronous API can be useful. But for well-designed queries/updates on tables with appropriate indexes, with the database API encapsulated inside generated classes, asynchronous is simple a non-starter.

    My thoughts here are focused on building business applications for mobile devices (e.g. smartphones).

    Reply

    1. Evan Ireland wrote on June 27th, 2010 at 2:50 pm:

      Looking at my own post, and after reviewing the spec (http://www.w3.org/TR/IndexedDB), I see:

      The spec does allow a synchronous API, but seemingly not one that is usable by the UI thread.

      The spec does allow for alternate indexes, but it is not clear if they can be composite.

      So I’ll need to dig a bit deeper to see whether we can expect a synchronous API usable by the UI thread as well as composite indexes.

      Reply

      1. Shawn Wilsher wrote on June 30th, 2010 at 9:21 am:

        I don’t think any browser vendor is willing to implement a synchronous API on the UI thread. This is what worker threads are for.

        Composite indexes are something being discussed still in the working group.

        Reply

    2. Shawn Wilsher wrote on June 30th, 2010 at 9:22 am:

      I think you are directly mapping the concept of tables to this API, which is not an efficient way to use it.

      Reply

  29. Brazilian Joe wrote on July 5th, 2010 at 2:45 pm:

    I think it is too convoluted. When working with javascript, I would like to think of the storage as javascript objects and forgo with SQL notions like tables.

    If I have to partition my data , I would simply add a ‘type’ property to all my objects and categorize them.

    I posted my ideas with more detail on my blog, should you want to read it.

    Reply

  30. Jeffry Engert wrote on July 9th, 2010 at 11:16 pm:

    the example of adding data gives an object is immutable error Problem with the example: objectStore(\kids\) will open the objectStore as read only… objectStore(\kids\,0) will open it for read/write.

    Reply

    1. Shawn Wilsher wrote on July 10th, 2010 at 11:29 pm:

      Yeah, we wrote this code long before we had builds working, which means it wasn’t ever tested (and may have bugs like what you found). I’m working on a new demo that actually runs in builds (and can be interacted with).

      Reply

  31. Michal Gielda wrote on July 14th, 2010 at 4:25 am:

    Hi guys,

    I was very happy to find out that IndexedDB made it into the first beta and decided to prepare a little demo/simple higher-level API with limited functionality so that you can just grab it and test it indexedDB for yourselves. I put it up on my company’s blog: http://antmicro.com/blog/2010/07/async-indexeddb-js-api-test/

    Please let me know if it works for you :) of course it’s far from complete, plus I’m not really a js coder (we mostly do embedded systems) so do not hesitate to tell me if things could be improved.

    I’ll try to add some more functionality to it in follow-ups.

    Cheers,
    Michael

    Reply

    1. Michal Gielda wrote on July 14th, 2010 at 4:27 am:

      or you can just use antmicro.com/blog.html :)

      Reply

    2. Shawn Wilsher wrote on July 19th, 2010 at 12:05 pm:

      Nice! Thanks for doing that!

      Reply

  32. Anentropic wrote on July 17th, 2010 at 5:45 am:

    From my reading of the draft spec, it is possible to:

    1. use Object or Array instances as values, eg:
    var abraham = {id: 1, name: ‘Abraham’, number: ’2107′};
    store.put(abraham);
    effectively this is a ‘row’ with threee ‘fields’ (‘id’ is an auto-generated index)
    2. define an additional index on the ‘name’ field of your stored Objects
    3. return records from a range of values, sorted by the index on ‘name’ eg:
    var range = new KeyRange.bound(‘L’, ‘M’);
    var cursor = index.openCursor(range);

    Great so far. In the section on ‘keys’ the spec says:
    “Only data types with natural ordering can be used as keys.”

    But what happens if we have data like:
    var abraham = {id: 1, name: ‘Abraham’, number: ’2107′, address: {postcode: ‘NW1 1AA’, city: ‘London’}};

    I think this is permitted to store that as a value, but what happens if you create an index on the ‘address’ field? Is that allowed? Seems like it would then need to behave as a key, with the restriction to types that have a ‘natural order’.

    Ideally I’d like to be able to create an index on a complex type and supply a comparison function for the engine to use when sorting the index. (or alternatively some kind of path syntax, eg an index on ‘address.postcode’)

    Indexes with composite keys would also be useful.

    Reply

    1. Shawn Wilsher wrote on July 19th, 2010 at 12:10 pm:

      While you can store an Array as a value, you cannot use it as a key.

      In the working group, we are discussing the possibility of composite keys, but they may be left out of the first version (so that we can get something stable shipping, and then start adding features).

      Reply

  33. Daniel wrote on July 20th, 2010 at 7:30 am:

    I don’t like the IndexedDB approach and would highly appreciate if all major browsers would implement the same api instead.
    As webkite and opera already support Web SQL (SQLLite) I think it is a very bad decision to take another route just for some academical reasons.
    I am using GWT to implement my JavaScript apps so it would be possible to add a GWT layout on top of Web SQL to provide a cleaner API if you are not able to live without it.
    But if choosing another approach it should at least support all the features of SQL Lite, otherwise it is worthless.
    So please: Add support for SQLLite so that web developers are not forced to use Google Gears to be able to implement offline capable rich web applications that run on all major browsers!

    Reply

  34. Anentropic wrote on July 21st, 2010 at 4:24 pm:

    I’m getting:

    Error: uncaught exception: [Exception... "Component returned failure code: 0x80460002 (NS_ERROR_OBJECT_IS_IMMUTABLE) [nsIIDBObjectStore.add]” nsresult: “0×80460002 (NS_ERROR_OBJECT_IS_IMMUTABLE)” location: “JS frame :: http://test/load.html :: anonymous :: line 74″ data: no]

    …when I try and add an entry to my new objectStore. No onerror event is fired but I see that in the HUD and execution of my loop halts at this point, the first iteration.

    Any ideas why?

    Everything else has worked up to that point, ie creating/opening the db according to examples above.

    Reply

    1. Shawn Wilsher wrote on July 21st, 2010 at 4:43 pm:

      You are in a READ_ONLY transaction for that object store. Make sure you open it as READ_WRITE. We need to improve that error message (I hit it and spent an hour trying to figure out what was up).

      Reply

      1. Anentropic wrote on July 22nd, 2010 at 2:15 am:

        Hi Shawn,

        Thanks for the info. I can probably track it down from that. I assume your ‘add kids’ code example above must have the same problem since neither of us are explicitly doing any transaction stuff? (the default is READ_ONLY then?)

        Would be great to see some more explanation of the transactions. For example I’m not really clear why you used a transaction in the JOIN example since you’re only reading and not writing.

        I already sussed that you have to use the moz_ prefix on indexedDB thanks to the Antmicro guys above…

        Reply

        1. Anentropic wrote on July 22nd, 2010 at 2:23 am:

          P.S.
          more than improving the error message… shouldn’t the actual onerror handler get called maybe?

          In the spec it says:
          “Any number of readers may concurrently access all object stores. A writer is not allowed if there is any reader concurrently accessing the object stores”

          So it sounds like any time you do a write there’s the possibility it bounces due to transaction locking, which even could be a process in another tab, beyond your control I guess?

          Or the correct procedure would be to attempt to get a READ_WRITE transaction before writing, and that attempt will fail gracefully where the raw add() does not? Guess I’ll have to try it!

          thanks

          Reply

          1. Shawn Wilsher wrote on July 22nd, 2010 at 11:01 am:

            Current thoughts in the working group is that it’s more useful to throw at the call site when we know something is going to fail immediately instead of doing it asynchronously with events. It’s easier to debug, and developers get immediate feedback.

            If you have a write transaction, it will never bounce because you already have the lock needed for that object store. Locks do not automatically promote either, so if you open as READ_ONLY, it will always be READ_ONLY.

            Hope this clarifies things a bit more!

        2. Shawn Wilsher wrote on July 22nd, 2010 at 11:05 am:

          Sort of. The spec has changed a bunch, so this code isn’t exactly accurate anymore. But yeah, that code has the same issue.

          Note that every database operation has to be done inside a transaction.

          Reply

          1. Anentropic wrote on July 26th, 2010 at 10:54 am:

            Ah! I finally realised that you can get your objectStore from the transaction object and start using it immediately… you don’t have to wait for the transaction.oncomplete event (that gets fired after you’ve added your objects to the store or whatever).

            One thing that seems missing is the ability to delete a db? You can removeObjectStore but I don’t see the equivalent for a db.

  35. TK wrote on July 21st, 2010 at 11:48 pm:

    I am testing IndexedDB. I can insert data in the object store. However, I can not update the data stored in the object store. I attempted to use “add” method with two arguments as following code.
    ————————-
    transaction.objectStore(“my_object_store”).add(new_object, id).onsuccess = function(event) {
    //some code
    }
    ————————-
    First argument was “object” and second argument was “id” tnat should be updated. And, it failed. If you know, please teach how to update it.

    I am looking forward to the completion of Firefox 4.

    Reply

    1. Shawn Wilsher wrote on July 22nd, 2010 at 10:58 am:

      I suspect you have the same problem Anentropic has above you. You need to open the transaction as READ_WRITE in order to write to the object store. If you do not specify, the default is to open it as READ_ONLY.

      Reply

  36. TK wrote on July 22nd, 2010 at 12:15 pm:

    Thank you for the answer. However, I was not able to solve this problem by your answer. Because I am not a native speaker of English, I might not be able to explain this problem well for you. I know that I must open the transaction as READ_WRITE in order to write to the object store as you say. Therefore, I can “insert” the data in the object store. But I cannot “update” the data that I inserted in the object store once. And I want to know how to “update” the data. I did not succeed though I executed the above-mentioned code to “update” the data that I inserted in the object store once. It would be greatly appreciated if this explanation is useful for you.

    Reply

    1. Shawn Wilsher wrote on July 22nd, 2010 at 12:34 pm:

      This test code shows you how to modify an existing entry off of an object store:
      http://mxr.mozilla.org/mozilla-central/source/dom/indexedDB/test/test_key_requirements.html?force=1#33

      Reply

      1. TK wrote on July 22nd, 2010 at 11:50 pm:

        Thank you for your kindness!!! By reading test code that you showed me, I was able to understand how to update data that was inserted in a object store. By your kindness, I became to be able to use “modify” method and “addOrModify” method. I understand how to use them is related to how to create a object store. And, I will work to develop my web application by using indexedDB. I am looking forward to the completion of Firefox 4. Thank you really for this time.

        Reply

      2. TK wrote on September 9th, 2010 at 6:39 am:

        I updated Firefox 4 from beta 4 to beta 5. And I noticed that ObjectStore object did not have “modify” method and “addOrModify” method for IndexedDB on beta 5. But ObjectStore object seems to have “put” method and “clear” method on beta 5. To update a existing record, we seem to need to “clear” the existing record once and then “put” the new record.

        Reply

        1. Shawn Wilsher wrote on September 9th, 2010 at 10:50 am:

          Yeah, we’ve been tracking the spec changes pretty closely. See http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#object-store for what to expect.

          Reply

        2. TK wrote on September 16th, 2010 at 1:12 am:

          I wrote “To update a existing record, we seem to need to “clear” the existing record once and then “put” the new record.”. But, after that, I noticed that all records of the object store were cleared when “clear” method was executed with specifying the identification number of the existing record as the following code.
          ————————————————–
          var request = my_object_store.clear(id);
          ————————————————–
          Is my usage wrong or is that a bug?

          Reply

          1. TK wrote on September 19th, 2010 at 7:53 pm:

            I noticed that we should use “remove” method to delete the existing record as the following code.
            ———-
            ver request = my_object_store.remove(id);
            ———-
            I apologize for my offer of the erroneous information. So, to update a existing record on Firefox 4 Beta 6, we seem to need to “remove” the existing record once and then “put” the new record. But I hope that we can use “put” method without using “remove” method to update the existing record.

  37. TK wrote on July 28th, 2010 at 12:32 pm:

    I have been working on developing a web application by using IndexedDB. When I created two indexes for one object store, the program did not work as expected. Cannot we use two indexes for one object store? I think that we might want to retrieve a object store by two or more indexes.

    Reply

    1. Shawn Wilsher wrote on July 28th, 2010 at 1:05 pm:

      Your post is lacking any useful details for us to be actually able to help you.

      Reply

  38. Guido Tapia wrote on July 29th, 2010 at 4:58 pm:

    Isn’t continue a reserved keyword?? Does this mean that any IndexedDB code breaks JavaScript in non indexeddb browsers (Even if indexed db is disabled)?

    Reply

  39. TK wrote on July 30th, 2010 at 3:31 am:

    To explain the situation that I encountered, I wrote the sample code, and posted it yesterday. However, the post is not displayed today. Because the post was too long, that might not have been accepted by this comment system. I have the post now. I want to show it but I do not know how to show it for you.

    Reply

  40. Frank wrote on July 30th, 2010 at 8:42 am:

    Is IndexedDB portable between different operating systems? I am developing applications for ebooks which will save book contents in the database. It will be great for users if the database is portable between any operating systems.

    Reply

  41. TK wrote on July 30th, 2010 at 12:01 pm:

    Because I was not able to post, I created temporary web page.
    http://sites.google.com/site/usingindexeddb/

    It would be greatly appreciated if this explanation is useful for you.

    Reply

    1. TK wrote on August 12th, 2010 at 5:41 am:

      The execution result of the above-mentioned program seems to show that having two indexes for one object store is impossible. Is that a specification of IndexedDB or is my implementation wrong? I want to know it.

      Reply

      1. Shawn Wilsher wrote on August 12th, 2010 at 10:23 am:

        There is nothing in the spec or the implementation that would limit the number of indexes you could have on an object store (short of the number of properties you have on your objects).

        Reply

        1. TK wrote on August 12th, 2010 at 11:24 am:

          I see. It is wonderful. Then, why does a error occur when I create two indexes for one one object store in above-mentioned program?

          Reply

          1. Shawn Wilsher wrote on August 12th, 2010 at 11:40 am:

            It could be a number of reasons. If you think it’s wrong, you should file a bug about it.

        2. TK wrote on August 13th, 2010 at 10:08 am:

          It seems a bug. It exists in Firefox 4 beta 3 too.

          Reply

        3. TK wrote on August 13th, 2010 at 10:13 am:

          I am using Firefox 4 beta 3 on Mac OS 10.6.4 though it forgot to say.

          Reply

          1. TK wrote on August 24th, 2010 at 5:54 pm:

            To my regret, this bug remains in Firefox 4 beta 4.

  42. Sri wrote on August 4th, 2010 at 12:57 am:

    You can find an indexed db playground at http://tinyurl.com/ff-idxdb. It has examples for the APIs. Wrote it since I could not find documentation elsewhere. Hope it helps.

    Reply

    1. Michal Gielda wrote on August 4th, 2010 at 1:43 am:

      Brilliant! That’s a very clear and useful tool you’ve got there, thanks :)

      Reply

  43. Dwight Vietzke wrote on August 8th, 2010 at 8:53 pm:

    I have to give favor to the WebKit SQLite side of client side db’s. SQL works for many other programming implementations, so why not in Javascript too. The point is, Mozilla (IMHO) should have done the same thing as WebKit SQL or whatever you want to call it, just to create a near de facto standard. The more browsers using the same client side db’s syntax and style, the better. A missed opportunity because programmers prefer to lead than to follow.

    And that isn’t to say that IndexedDB isn’t good or better, just that having all future browsers using a common db strategy would have been wonderful (a guy can dream). IndexedDB could then become a leader in the next generation, additional db implementation for javascript. It would seem that IndexedDB has a place (document-centric or JSON based), but what we needed was a more common (dare I say standard) interface in javascript now.

    Reply

    1. Shawn Wilsher wrote on August 10th, 2010 at 7:09 am:

      Microsoft was very much against implementing WebDatabase, so even if Mozilla could ignore its issues with the specification, you still would not have had it all browsers. Contrast this with Mozilla, Webkit (via the chromium team), and Mozilla all committing to and working on the IndexedDB specification.

      Reply

      1. greg wrote on September 2nd, 2010 at 1:41 pm:

        So what if Microsoft was against developing IE with an SQLite DB, Shawn? Is that so much of a surprise since they market relational DB’s and were never likely to come on-board anyway. Issue’s with “the specification” seems like a wafer thin excuse not to implement what is becoming a popular back-end persistence layer. Is anyone actually in charge at Mozilla anymore?

        Reply

        1. Christopher Blizzard wrote on September 9th, 2010 at 10:09 am:

          Greg, your hyperbole doesn’t help get your message across at all.

          We’ve been pretty clear about what we think about the current database spec. There are real problems there, some of which are fundamental.

          And there’s interest from at least three of the major browser vendors to implement IndexedDB. That seems like it’s something worth investing in.

          Reply

  44. Morn Jaon wrote on August 11th, 2010 at 6:00 pm:

    I am a beginner of IndexedDB,here I wanna the answer to a stupid question from you:What kind of database file of IndexedDB use? .db? or .XML?

    Reply

    1. Shawn Wilsher wrote on August 12th, 2010 at 10:21 am:

      The API doesn’t specify it, so it doesn’t really matter.

      Reply

      1. Morn Jaon wrote on August 12th, 2010 at 10:13 pm:

        So,there’s no need to know what kind of database or where it located when we create a IndexedDB and use it?
        I am not good to IndexedDB’s API.most of them still look strange to me.I’m not a skilled web coder yet.

        Reply

        1. Shawn Wilsher wrote on August 13th, 2010 at 2:13 pm:

          No, it’s just a DOM API.

          Reply

          1. Morn Jaon wrote on August 15th, 2010 at 5:35 am:

            can you show me some tutoral or reference to study? I’m really need some to get a close understand of it.

  45. TK wrote on August 13th, 2010 at 1:24 pm:

    How should we think about the security of indexedDB? I am working to develop small web application using indexedDB, then I am taking measures against cross site request forgeries similar to server application to my application. That is, I send a request of user to server once, and I verify it, and finally I send the instruction to write data to indexedDB of user’s browser. But because JavaScript has “same origine policy”, I think it may not be necessary that I send a request to server and verify it. What do you think of this idea?

    Reply

    1. Shawn Wilsher wrote on August 13th, 2010 at 2:14 pm:

      I think this is something you should bring up to the working group.

      Reply

  46. Pete wrote on August 24th, 2010 at 9:17 am:

    For all who prefer the WebDatabase approach, there is an addon which exposes the WebDatase API to content. It’s called ZoooS Widget Runner:
    https://addons.mozilla.org/en-US/addon/70769/

    Reply

  47. Meni wrote on September 19th, 2010 at 12:53 am:

    I have just read this article, not the comments yet, so excuse me for rushing in to comment, if I make a fool of myself it’s only because i feel strongly about this situation. Isn’t this SVG vs VML all over again? From what I have read, it was egos and pride back then, and we all lost because of that. Had we have a agreed upon vector standard back then the web better today.

    What i’m arguing for is get the guys from Google, Apple, MSFT, Mozilla and Opera in a room, NO ONE leaves until we have white smoke. MOVE THE WEB FWD FAST. Ration the pizza while locked there :-)

    Sheesh, had JavaScript was to be created by a you guys, we would still be waiting for it today ;-) If there is a lesson to be learned i think it’s: choose something already, who cares if it’s less then perfect, no one is going to jail you for that.

    Good day (BTW, thks for FF, can’t live without it)

    Reply

    1. Greg Quinn wrote on September 19th, 2010 at 7:58 pm:

      > Sheesh, had JavaScript was to be created by a you guys,
      > we would still be waiting for it today ;-)

      Uhm, I think JavaScript *was* invented by these guys…

      Reply

      1. Emmanuel wrote on September 20th, 2010 at 2:01 pm:

        Javascript was invented by a single person/corporation (Brendan Eich/Netscape) in the beginning. If it had to be invented and agreed upon by a committee from several competing corporations from day 1, I wouldn’t be surprised that we’d waited 5 years before they agreed on what functions should be in it and another 5 before it was ratified and recommended for use and finally another 5 before we all had something that worked more or less similarly.

        The sad thing is, history has proven it again and again (VHS/BetaMax, HD/BluRay), we’ll all be forced to choose to learn one, or spend extra time on both until one finally wins in the market place.

        Clients only care about the end result on time, I just want what works and if I already know it, even better. If I have to learn something new, I will. I just don’t want to have to learn TWO just to do the same thing on all browsers. This stinks like the whole cross-browser compatibility rubbish again.

        Reply

  48. JoshuaBln wrote on September 23rd, 2010 at 1:37 am:

    Does Internet Explorer 9 beta support IndexedDB right now ?? I was not able to test my code on IE9 but it worked with Firefox 4.0 beta 6.

    Reply

  49. Matt wrote on November 1st, 2010 at 8:01 pm:

    I think exposing a B-Tree database as the foundation makes sense. I agree that using it directly looks overly complex, but we are really just a jQuery plugin away from elegance. You really can build a decent performing relational, hierarchal, or document oriented database atop this foundation.

    Hope this is adopted soon by the major browsers.

    Reply

  50. Joe Shawfield wrote on November 4th, 2010 at 3:13 am:

    I appreciate the efforts of those on the forefront of these decisions and discussions. It takes a lot to put your technical considerations and beliefs in front of everyone to ramble on about. It benefits us all greatly!

    I personally want both. I am on the SQL side of the syntactic likability factor for storing relationally structured data but I also love the javascript methods and programming models.

    I do see all kinds of situations, particularly on the web where I want/need to store objects. I want to persist them for later use in my client side applications.

    So I want both types of storage available at my disposal.

    What I come to at the end is if I use the SQL option, and need to use it or send it back home, I have a bit more Marshalling to do to use it on the client side or to get/send it over the http model. I have to pack it up at one end and unpack it at the other end.

    Thanks all

    Reply

1 2

Add your comment

  1.