Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Primary Key issue on iOS8 implementation of IndexedDb

The issue is when you have two different object stores in the same indexeddb, primary key values appear to be "shared" across all stores.

<body>     <script type="text/javascript">         //prefixes of implementation that we want to test window.indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;  //prefixes of window.IDB objects window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.msIDBTransaction; window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.msIDBKeyRange  if (!window.indexedDB) {     window.alert("Your browser doesn't support a stable version of IndexedDB.") }   var db; var request = window.indexedDB.open("newDatabase", 4);  request.onerror = function(event) {   console.log("error: "); };  request.onsuccess = function(event) {   db = request.result;   console.log("success: "+ db); };  request.onupgradeneeded = function(event) {         var db = event.target.result;         var objectStore = db.createObjectStore("customers", {keyPath: "arseid"});     var objectStore = db.createObjectStore("test", {keyPath: "id"}); }    function add1() {         var x = new Date();     var h1 = x.getHours();     var m1 = x.getMinutes();     var s1 = x.getSeconds();     console.log('starting insert on ' +  h1 + ':' + m1 + ':' + s1);      var tx = db.transaction(["customers"], "readwrite");     for (var i = 0; i < 1000; i++) {         var request = tx.objectStore("customers")                 .put({ arseid: i, name: "Jonathan Smith", email: "[email protected]", favourite: "chocolate cake", pet: "rudolph the red nose reindeer", address: "999 letsbe avenue, townton, countyshire" });     }       tx.oncomplete = function (e) {             // Re-render all the todo's             var x2 = new Date();              var h2 = x2.getHours();              var m2 = x2.getMinutes();              var s2 = x2.getSeconds();                 console.log('transaction complete ' + h2 + ':' + m2 + ':' + s2);         } }   function add2() {     //tx 2     var tx2 = db.transaction(["test"], "readwrite");     for (var i = 0; i < 1000; i++) {         var request2 = tx2.objectStore("test")                 .put({ id: i, name: "Robwin Mwengway", email: "[email protected]", favourite: "chocolate cake", pet: "rudolph the red nose reindeer", address: "999 letsbe avenue, townton, countyshire" });     }      tx2.oncomplete = function (e) {             var x3 = new Date();              var h3 = x3.getHours();              var m3 = x3.getMinutes();              var s3 = x3.getSeconds();                 console.log('transaction complete ' + h3 + ':' + m3 + ':' + s3);         } }       </script> <button onclick="add1()">Add1 data to indexedDb</button> <button onclick="add2()">Add2 data to indexedDb</button> </body> 

(Fiddle: http://jsfiddle.net/jonnyknowsbest/4pdp8vxe/)

In iOS8, if you run up the fiddle and click "Add1 data to IndexedDb", then 1000 entries get added to the "customers" table. If you then click "Add2 data to IndexedDb", then 1000 entries get added to the "suppliers" table, but the 1000 from the "customers" is removed.

Has anyone else come across this? Is this part of the IndexedDb specification? Chrome does not seem to have this problem.

EDIT: Found this W3 Org IndexedDB Recommendation: "There can never be multiple records in a given object store with the same key." Apple seem to have applied this at the database level.

like image 657
Jonathan Smith Avatar asked Sep 24 '14 14:09

Jonathan Smith


People also ask

What is key path in IndexedDB?

In short, the indexName is how we want to the "field" or "column" (index) will be named in our "table" (Object Store) and the keyPath is the property of the stored object that contains the value of the field.

How can you insert a new record collection of data in IndexedDB?

add() adds a new record to the store. IDBCursor. update() updates the record at the current position of the cursor.

Can I store object in IndexedDB?

It lets you store just about anything in the user's browser. In addition to the usual search, get, and put actions, IndexedDB also supports transactions. Here is the definition of IndexedDB on MDN: IndexedDB is a low-level API for client-side storage of significant amounts of structured data, including files/blobs.


1 Answers

I can confirm that iOS8 is definitely buggy here. I tried a few workarounds, but the best I can suggest is a primary key that combines some unique string, like the name of the objectStore, with a number. So for example, given two objectStores called people and notes, I'd store data with keys like so:

people/X notes/X

You can set X manually, or, use the .count() method on the objectStore to find the count and add one. Here is an example:

//Define a person var person = {     name:"Ray",     created:new Date().toString(), }  //Perform the add db.transaction(["people"],"readwrite").objectStore("people").count().onsuccess = function(event) {     var total = event.target.result;     console.log(total);     person.id = "person/" + (total+1);      var request = db.transaction(["people"],"readwrite").objectStore("people").add(person);      request.onerror = function(e) {         console.log("Error",e.target.error.name);         //some type of error handler     }      request.onsuccess = function(e) {         console.log("Woot! Did it");     }  } 

Note that I specified keyPath of "id" for this OS.

like image 147
Raymond Camden Avatar answered Sep 29 '22 08:09

Raymond Camden