0

I've been trying to update a single field using db.put() but couldn't make it work properly. Every time I update a single field by a given ID, it deletes all other entries. Here is an example code:

 var schema   = {
            stores: [
                {
                    name: 'items',
                    keyPath: 'id'
                },
                {
                    name: 'config',
                    keyPath: 'id'
                }
            ]
        };

        var db = new ydn.db.Storage('initial', schema);
        var items = [{
            id: 1,
            itemId: 'GTA5',
            date:'03/25/2013',
            description:'Great game'
        }, {
            id: 2,
            itemId: 'Simcity',
            date:'12/01/2012',
            description:'Awesome gameplay'
        }];
        var config = {
            id: 1,
            currency: 'USD'
        };
        db.put('items', items);
        db.put('config', config);

var updateTable = function(){
        var req = $.when(db.count('items'),db.values('items'),db.get('config', 1));
        var disp = function(s) {
            var e = document.createElement('div');
            e.textContent = s;
            document.body.appendChild(e);
        };
        req.done(function(count,r,config) {
            var currency = config.currency;
            if(count > 0){
                var n = r.length;
                for (var i = 0; i < n; i++) {
                    var id    = r[i].id;
                    var itemId = r[i].itemId;
                    var date = r[i].date;
                    var description = r[i].description
                    disp('ID: '+id+' itemID: '+itemId+' Currency: '+currency+' Date: '+date+' Description: '+description);
                }
            }
        });
}

updateTable();

$('a').click(function(e){
    e.preventDefault();
    db.put('items',{id:2,description:'Borring'}).done(function(){
        updateTable();
    });
});

Here is a working example of whats happening JSFiddle. If you click the "change" link, the specified field is updated but all other fields are 'undefined'

Kyaw Tun
  • 12,447
  • 10
  • 56
  • 83
Crash Override
  • 411
  • 6
  • 17

1 Answers1

1

Yeah, SimCity is boring now, but Tomorrow will bring excitement again.

IndexedDB is essentially a key-document store. You have to read or write a record as a whole. It is NOT possible to update only certain field(s). Event if you want small update, you have to read and write back whole record.

Reading and write back the whole record is OK, but there is an important consideration for consistency. When you write back, you must ensure that the the record you have was not modified by other thread. Even though javascript is single thread, since both read and write operations are asynchronous and each operation could have different database state. It seems extremely rare, but often happen. For example, when user click, nothing happen and then click again. These user interactions are queued and execute in parallel from async database perspective.

A common technique is using single transaction for both operations. In YDN-DB, you can do in three ways.

Using explicit transaction:

db.run(function(tx_db) {
  tx_db.get('items', 2).done(function(item) {
    item.description = 'boring until Tomorrow';
    tx_db.put(item).done(function(k) {
      updateTable();
    }
  }
}, ['items'], 'readwrite');

Using an atomic database operation:

var iter = ydn.db.ValueIterator.where('items', '=', 2);
db.open(function(cursor) {
  var item = cursor.getValue();
  item.description = 'boring until Tomorrow';
  cursor.update(item);
}, iter, 'readwrite');

EDIT:

Using query wrapper:

db.from('items', '=', 2).patch({description: 'boring until Tomorrow'});  
Kyaw Tun
  • 12,447
  • 10
  • 56
  • 83
  • Is there a way to wrap this in a function so it can be re-used over and over? If so, is it too much to ask to make a working example on fiddle? I'm just starting with asynchronous programing and its kind of overwhelming sometimes. And to be honest, your API is amazing and fits my project perfectly. Thanks! – Crash Override Oct 03 '13 at 17:53
  • Look like a nice suggestion. A have added in query wrapper as `patch` method. See doc for detail: http://dev.yathit.com/api-reference/ydn-db/query.html Thanks. – Kyaw Tun Oct 04 '13 at 08:15
  • That looks amazing, can I add a callback to `patch()`? so I can execute other functions after update is done? Thanks and have a great day! – Crash Override Oct 04 '13 at 11:09
  • Yes. you can. In this example, it is simple, since there is only one query result. – Kyaw Tun Oct 04 '13 at 13:03