3

When attempting to update a record within indexeddb using the put method, it appears that a new value is created rather than a change. According to MDN this is the method to update a record, yet I'm not having the expected result. Any ideas? Here is my code example.

/*
    @keys initalisation
*/
extension.onupgradeneeded = function (event) {
    database = event.target.result;

    if (!database.objectStoreNames.contains('profile')) {

        var _profile = database.createObjectStore('profile', { autoIncrement: true });

        _profile.createIndex('default', 'default', { unique: true });
        _profile.createIndex('username', 'username', { unique: true });

        _profile.transaction.oncomplete = function (_oncompleteEvent) {

             app.database.store(database, 'profile', {
                default: true,
                username: 'my name', 
                image: 'images/svg/menu.svg' 
             });
        };
}

var app = {
    database: {
        update: function (_database, _datakeys, _key, _value, _function) {
            /*
                @pass database object, array / string, string, object, callback
            */
            var _updateRequest = _database.transaction(_datakeys, "readwrite").objectStore(_key).put(_value);

            _updateRequest.onerror = function (event) {
                try {
                    _function.error(event);
                } catch(err) {
                    console.log('An error was encountered', event.target.error.name);
                }
            };

            _updateRequest.onsuccess = function (event) {
                try {
                    _function.success(event);
                } catch (error) {
                    _function(event);
                }
            };
        }
    }
};

/*
    @how I call the function
*/

app.database.update(database, 'profile', 'profile', {default: false, username: 'hello world', image: 'http://imagepath.com' }, {
    error: function () {
        alert('failed');
    },
    success: function (returnedData) {
        console.log(returnedData);
    }
);
lindsay
  • 972
  • 2
  • 11
  • 21

1 Answers1

6

Are you using in-line or out-of-line keys?

  • If in-line, you need to set the id (whatever you named it) property in the object before using store.put.
  • If out-of-line, you need to pass the id property value as the second parameter to store.put.

Edit: if you have no idea whether the keys are in-line or out-of-line, review the following:

Every object store must have a name that is unique within its database. The object store can optionally have a key generator and a key path. If the object store has a key path, it is using in-line keys; otherwise, it is using out-of-line keys.

If you are using in-line, and you are setting the property, and it is still performing an insert instead of an update, try console.log('The object passed to put is %o', objToPut); before calling store.put, and verifying whether the id property (or whatever you named the primary key of the store) is defined and has the expected value (its id).

If you are not using a key for the store, then all puts will be inserts, because indexedDB has no way to of knowing which object to update. If you want to do that anyway, maybe you could get away with using openCursor on the object you want to change and then using cursor.update to replace that object.

Josh
  • 17,834
  • 7
  • 50
  • 68
  • Thank you for the very comprehensive answer, really appreciative. I'm not sure of the keys I am using. I'll include the database keys in the answer so it might be a bit more clear. Additionally, could you profile a code example of setting the ID? – lindsay Aug 05 '14 at 02:14
  • 1
    I recognized that it wasn't clear right as you were typing and edited the answer to include a link to some helpful reading material to learn about key types. – Josh Aug 05 '14 at 02:16
  • 1
    Ok, looking at the code, you do not have a keyPath property set in the object that is the second argument to `createObjectStore`. This means out-of-line. So you need to pass profile.id when using put as the 2nd argument. Like `store.put( profileObject, profile.username)`, if username is what you consider to be the key. – Josh Aug 05 '14 at 02:20
  • Genius! So, if I wanted to update multiple values would I need to call `put` for each instance? Eg. `profile.image = 'x';` `store.put(profileObject, profile.image')`? – lindsay Aug 05 '14 at 02:22
  • 1
    Yes. There are some batch operations available in indexedDB's API, but store.put is not one of them. – Josh Aug 05 '14 at 02:23
  • Thanks so much @Josh, I'll try out these news methods and see how I go. Thank you for your code examples and resource! – lindsay Aug 05 '14 at 02:26
  • just writing back to confirm that I've got my program editing values. Thank you very much! – lindsay Aug 12 '14 at 00:32