indexedDb - 使用两个独立密钥保存/更新(本地和服务器ID /在线和离线)

时间:2014-10-09 14:19:35

标签: javascript indexeddb

我想编写一个Angular模块,在本地保存数据(使用IndexedDB),并通过RESTful服务将数据与服务器数据同步。

我已经为那些已经可以将数据传输到服务器并将其放入IndexedDB的基础构建了一个基础。

由于Web应用程序也必须在脱机模式下运行,因此我选择使用两个键作为对象库。 autoIncremented的本地ID和服务器上条目的ID。

服务器不知道本地ID,如果无法将服务器ID传输到服务器,本地数据条目可能不知道

当我为服务器ID定义唯一索引时,如果服务器ID已存在且更新过程停止,则本地条目将不会更新。

有没有办法直接使用IDB API?

我发现了类似的问题,但是使用简单的游标和cursor.update解决方案,不可能将新数据从服务器插入本地数据库: Indexeddb - Update record by index key

1 个答案:

答案 0 :(得分:0)

我找到了一种方法。我将与服务器数据分开处理本地数据(带有本地ID)(没有本地ID,因为服务器不知道它)。

然后我将使用IDBObjectStore.put更新本地数据,并检查来自服务器的数据(服务器ID是否已设置,但没有本地ID)是否已在本地保存,并具有单独的IDBIndex.openCursor调用。如果在给定的serverId中找到了本地数据,则会添加一个带有IDBObjectStore.put的新条目,如果找到,则该条目上的光标将使用服务器数据进行更新(旧的localId将被转移)。

// var _db => connected database

// filter the data that came from the server (no local id defined but server id is)
var serverData = [];
for (var i = 0; i < data.length; i++) {
  if (data[i]._localId === undefined && data[i].serverId !== undefined && data[i].serverId !== null) {
    // remove the server data object and add it to the server data array
    serverData = serverData.concat(data.splice(i, 1)); 
    i--;
  }
}

var transaction = _db.transaction(_storageName, 'readwrite');

transaction.oncomplete = function() {
  // do something on completion
};

transaction.onerror = function(e) {
  // do something when an error occurs
};

var objectStore = transaction.objectStore(_storageName);

// Add local data to the database (no server id)
// local id can be existing or not (new entry)
for (var i = 0; i < data.length; i++) {
  objectStore.put(data[i]).onsuccess = function(e) {
    // do something when successfully added
  };
}

// Add data from the server to the database
var index = objectStore.index('serverId'); // server id index for searching
// go through all data from the server
for (var i = 0; i < serverData.length; i++) {
  (function(){
    var serverItem = serverData[i];
    // search for an existing entry in the local database
    var checkRequest = index.openCursor(IDBKeyRange.only(serverItem.serverId));
    checkRequest.onsuccess = function (e) {
      var cursor = e.target.result;
      // If item was not found in local indexedDB storage...
      if (cursor === null) {
        // add new item to storage
        this.source.objectStore.put(serverItem).onsuccess = function(e) {
          // do something when successfully added
        };

      // Item was found locally
      } else {
        var dbItem = cursor.value;
        // set local id of the added item to the one from the old local entry
        serverItem.localId = dbItem.localId; 
        // update found local entry with the one from the server
        cursor.update(serverItem).onsuccess = function(e) {
          // do something on success
        };
      }
    };
  })();
}

可能会有一个更优雅的解决方案,但这个是我提出的第一个解决方案。我会感谢任何改进或更好的解决方案。