IndexedDB的 Package 函数

bybem2ql  于 2023-10-14  发布在  IndexedDB
关注(0)|答案(5)|浏览(157)

我需要为iPad/平板电脑设备构建一个离线HTML5 Web应用程序,用户可以从服务器下载数据集(数据表)并将其存储在设备上。然后,用户可以断开与服务器的连接,并在设备上本地查看/编辑数据。这是为那些在偏远地区工作的人,那里没有Hive网络覆盖,需要收集/更新数据。当他们回到办公室时,他们可以将数据同步/上传回服务器。它需要HTML5的原因是它的平台无关,即可以在iOS,Android等上运行它,只要它有一个支持HTML5的现代Web浏览器。
现在我已经使用HTML5本地存储(用于数据)和HTML5离线应用程序缓存(用于页面/css/js/图像)构建了系统,它可以很好地处理小数据集(我可以在离线时查看,编辑和保存,在线时加载/同步)。现在我需要扩展到10,000行数据。它的工作,但它是相当慢,挂起浏览器10秒,而加载在英特尔四核8 GB的机器。
所以我一直在研究一些比本地存储更好的替代方案:
1)WebSQL:能够使用SQL语言查询数据并进行连接等。问题是它现在已经过时了,不再受支持,所以我不想花时间为它构建一些东西。
2)IndexedDB:使用对象存储(从技术上讲,我已经使用本地存储API存储对象,并使用JSON存储)。潜在的更快,因为它使用SQL Lite后端的索引。有很多样板代码可以完成简单的任务,比如创建数据库、向数据库添加数据、从数据库中阅读数据、迭代数据库。我只想做一个像select(xyc, abc).where(abc = 123).limit(20)这样的简单查询,但却不得不编写大量的JavaScript代码来完成它。如何编写自己的代码来进行表之间的连接,有任何例子吗?
我发现了一个jQuery plugin可以让生活更简单。有没有其他的或者其他的库可以减轻使用IndexedDB的痛苦?
多谢了!

c6ubokkw

c6ubokkw1#

我有一个开源的web database wrapper,它同时支持IndexedDB和WebSql。
版本迁移在感知之后处理。下面的代码将迁移(或初始化)到版本2。

schema_ver2 = {
    version: 2,
    size: 2 * 1024 * 1024, // 2 MB
    stores: [{
        name: 'ydn_obj',
        keyPath: 'id.value',
        indexes: [{
            name: 'age',
            type: 'INTEGER'  // type is require for WebSql
        }]
    }]
}
db = new ydn.db.Storage('db name', schema_ver2)

Query非常灵活和强大。举例来说:

q = db.query('customer').when('age', '>=', 18 , '<', 25).where('sex', '=', 'FEMALE')
young_girls = q.fetch(10, 2); // limit and offset

再次使用更有效的键范围查询,如果年龄被索引:

q = db.query('customer', 'age').bound(18, 25, true).where('sex', '=', 'FEMALE')

支持transaction

p123 = db.tkey('player', 123);
db.runInTransaction(function() {
   p123.get().success(function(p123_obj) {
        p123_obj.health += 10;
        p123.put(p123_obj);
   });
}, [p123]);
5uzkadbs

5uzkadbs2#

试试linq2indexeddb。它有你想要的查询接口+与indexeddb shim for websql的WebSQL API也支持。

n3ipq98p

n3ipq98p3#

你有没有考虑过【草坪椅】?它提供了一个很好的底层存储抽象,还有用于查询,聚合和分页数据的插件。作为查询的示例:

// basic searching
    this.where('record.name === "brian"', 'console.log(records)') 
    this.where('record.name != ?', username, 'console.log(records)')

    // sorting results
    this.where('name === "brian"').asc('active', 'console.log(records)')

我能看到的唯一潜在缺点是,它似乎不能处理迁移,并且通用似乎没有创建索引等的方法。
关于连接,IndexedDB被设计为面向文档(无SQL)的存储,而不是关系数据库,但是考虑到这是一个常见的场景,似乎有两个选项:
1)2)如果上面的方法太慢,你也可以创建一个专用的键值对象存储,然后可以用来在相关的存储中进行索引查找。这可能是一件苦差事,具体取决于您的加入需求的数量。

ldioqlga

ldioqlga4#

我认为JsStore会为你工作。
假设你的查询在sql中看起来像这样-
select * from table_name where column1='abc' limit 20
JsStore-它将是

var Connection = new JsStore.Instance("YourDbName");
Connection.select({
    From: "table_name"
    Where: {
        Column1: 'abc',
    },
    Limit:20,
    OnSuccess:function (results){
        console.log(results);
    },
    OnError:function (error) {
        console.log(error);
    }
});

所以你可以用JsStore写类似于sql的查询。

1qczuiv0

1qczuiv05#

将IndexedDB的 Package 器版本同步到localStorage API。我找不到这些 Package 器的任何同步版本,因为IndexedDB是同步的,localStorage是同步的,所以我需要做一些黑客https://gist.github.com/xnohat/b7aa5035278478871697b7ad6255efb2

class IndexedDBStorage {
  constructor(dbName = 'localStorageDB', storeName = 'localStorageStore') {
      this.dbName = dbName;
      this.storeName = storeName;
      this._init();
      this.cache = {};
  }

  _init() {
      const request = window.indexedDB.open(this.dbName, 1);
      request.onerror = (event) => console.error('Error opening indexedDB');
      request.onsuccess = async (event) => {
          this.db = event.target.result;
          await this._populateCache();
          this._syncCache();
      };
      request.onupgradeneeded = (event) => {
          const db = event.target.result;
          db.createObjectStore(this.storeName);
      };
  }

  async _populateCache() {
      const store = this._getStore();
      return new Promise((resolve, reject) => {
          const request = store.openCursor();
          request.onsuccess = (event) => {
              const cursor = event.target.result;
              if (cursor) {
                  this.cache[cursor.key] = cursor.value;
                  cursor.continue();
              } else {
                  resolve(); // Finished populating the cache
              }
          };
          request.onerror = (event) => reject('Error populating cache');
      });
  }

  async _syncCache() {
      for (const key in this.cache) {
          await this._asyncSetItem(key, this.cache[key]);
      }
  }

  async _asyncSetItem(key, value) {
      const store = this._getStore('readwrite');
      return new Promise((resolve, reject) => {
          const request = store.put(value, key);
          request.onsuccess = () => resolve();
          request.onerror = (event) => reject('Error storing value');
      });
  }

  _getStore(mode = 'readonly') {
      const transaction = this.db.transaction([this.storeName], mode);
      return transaction.objectStore(this.storeName);
  }

  setItem(key, value) {
      this.cache[key] = value;
      this._asyncSetItem(key, value).catch(console.error);
  }

  getItem(key) {
      if (this.cache[key]) {
          return this.cache[key];
      }
      // Fetch from indexedDB and store in cache (in the background)
      this._asyncGetItem(key).then(value => {
          this.cache[key] = value;
      });
      return null; // or some default value
  }

  async _asyncGetItem(key) {
      const store = this._getStore();
      return new Promise((resolve, reject) => {
          const request = store.get(key);
          request.onsuccess = (event) => resolve(event.target.result);
          request.onerror = (event) => reject('Error retrieving value');
      });
  }

  removeItem(key) {
      delete this.cache[key];
      this._asyncRemoveItem(key).catch(console.error);
  }

  async _asyncRemoveItem(key) {
      const store = this._getStore('readwrite');
      return new Promise((resolve, reject) => {
          const request = store.delete(key);
          request.onsuccess = () => resolve();
          request.onerror = (event) => reject('Error removing value');
      });
  }

  clear() {
      this.cache = {};
      this._asyncClear().catch(console.error);
  }

  async _asyncClear() {
      const store = this._getStore('readwrite');
      return new Promise((resolve, reject) => {
          const request = store.clear();
          request.onsuccess = () => resolve();
          request.onerror = (event) => reject('Error clearing store');
      });
  }
}

const idbStorage = new Proxy(new IndexedDBStorage(), {
  get: (target, prop) => {
      if (typeof target[prop] === 'function') {
          return target[prop].bind(target);
      }
      return target.getItem(prop);
  },
  set: (target, prop, value) => {
      target.setItem(prop, value);
      return true;
  }
});

window.idbStorage = idbStorage;

相关问题