IndexedDB: Modifying pre-existing objects in an object store

2k views Asked by At

I am trying to wrap my head around IndexedDB.

I created an object store that uses a key-generator with no key-path.

var objectStore = db.createObjectStore("domains", {autoIncrement: true });
objectStore.createIndex("domain", "domain", { unique: true, multiEntry: true });

In order to access my records, I created an index that references my object store. The index's key path is the domain property of my records.

Here is an example of what one record in my object store might look like:

{ domain: ["stackexchange",
           "stackoverflow",
           "superuser",
           "askubuntu",
           "serverfault"], 

  bold          : ["<strong>",1], 
  italic        : ["<em>",1],
  strikethrough : ["<del>",1],
  superscript   : ["<sup>",1],
  subscript     : ["<sub>",1],
  heading1      : ["<h1>",1],
  heading2      : ["<h2>",1],
  heading3      : ["<h3>",1],
  blockquote    : ["<blockquote>",1],
  code          : ["<code>",1],
  newline       : ["<br>",2],
  horizontal    : ["<hr>",2]
},

Each entry appearing in the domain property is guaranteed to be unique among the set consisting of the union of every domain key's value out of every record of my object store. I.E. You won't find any of these domains anywhere else in my object store.

I need to let user's edit the objects in the object store. Provided with a single domain, I can retrieve the associated object like this:

var DBOpenRequest= window.indexedDB.open(db_name, db_version);
DBOpenRequest.onsuccess= function(event){   
    var db= DBOpenRequest.result;
    var domains=db.transaction('domains', 'readwrite').objectStore('domains');

    var query = domains.index("domain").get("stackoverflow");   
};

Now, here is the part where I am confused. Once the user has changed the properties that they want to edit/added new properties as they please, I need to save their changes by replacing the object retrieved above with the new object that the user created. (or modify the original object and save the changes).

I think I need to use IDBObjectStore.put() to do this.

The put() method takes two parameters, one required and one optional:

value
    The value to be stored.
key
    The key to use to identify the record. If unspecified, it results to null.

The second parameter is presumably optional for the instances in which you are using inline keys. I am using out-of-line keys that were generated with a key generator.

How can I get the (auto-generated, out-of-line) key of the object that I retrieved through my index, so I can communicate to the object store that I want to modify that pre-existing object and not create a new one?

Is there another way I should be going about this?

2

There are 2 answers

6
hagrawal7777 On BEST ANSWER

Below is the text from IndexedDB specs for indexes.

Each index also has a unique flag. When this flag is set to true, the index enforces that no two records in the index has the same key. If a record in the index's referenced object store is attempted to be inserted or modified such that evaluating the index's key path on the records new value yields a result which already exists in the index, then the attempted modification to the object store fails.

So, "put()" cannot be used if a unique index is created on that property. So, instead you can create a primary key i.e. use keyPath while creating object store.

var objectStore = db.createObjectStore("domains", {keyPath: "domain"});

Check below 2 URLs which will help you get more insight that it is not possible to perform an update if a unique index exists on it.

0
Luke On

To future readers. As an alternative to using the keypath:

Rather than using IDBObjectStore.put() you can iterate over the objects in the object store with IDBObjectStore.openCursor()

Once you hit the object you are looking for, you can either use: