使用IndexedDB获取所有数据及其键值

18

通过使用IndexedDB API,我们有以下两种方法:getAll()getAllKeys(),下面是一个使用示例:

let transaction = this.db.transaction(["table"]);
let object_store = transaction.objectStore("table");
request = object_store.getAll(); /* or getAllKeys() */

request.onerror = (event) => {
    console.err("error fetching data");
};
request.onsuccess = (event) => {
    console.log(request.result);
};

问题在于getAll()似乎仅以数组格式检索数据,而getAllKeys()获取所有键但不包含数据。我找不到一种同时获取键和值的方法。

  1. 难道没有更好的方式能够一次调用获取数据键吗,就像它们存储在内存中一样?

  2. 如果没有,那么有没有更好的方式可以处理这个问题,而不会让代码过于混乱,产生多个异步调用的情况?


嗯,不太确定如何理解这个问题。有点不清楚,回答也不够明确。或者说不知道为什么会被赞。但你可以使用 getAll 并访问每个对象的属性... - Josh
3
@Josh 在找到解决方法后,我已经回答了自己的问题。为了澄清一下:当然你可以用 getAll() 访问所有对象的属性,但不能访问存储在 IndexedDB 表中的对象键。表存储将内容存储为“键:对象”对的列表形式。getAll() 只提供对象,getAllKeys() 只提供键。我想要一种方法来检索键和对象(或数据),而不需要多个异步调用。 - TheMechanic
使用内联键和getAll。 - Josh
4
刚看到这个,发现Mechanic的解决方案很合适。内联密钥是相当糟糕的做法,这是数据重复,需要不断保持同步。 - GullerYA
2个回答

24

使用像这样的 IDBCursor,我可以使用一个回调函数检索所有值及其键:

transaction = this.db.transaction(["table"]);
object_store = transaction.objectStore("table");
request = object_store.openCursor();

request.onerror = function(event) {
   console.err("error fetching data");
};
request.onsuccess = function(event) {
   let cursor = event.target.result;
   if (cursor) {
       let key = cursor.primaryKey;
       let value = cursor.value;
       console.log(key, value);
       cursor.continue();
   }
   else {
       // no more results
   }
};

1
在我看来,更好的解决方案是分别调用getAllKeys和getAll,并利用结果以相同方式排序的事实。从getAll获取的第n个值与从getAllKeys获取的第n个键匹配。 - l1b3rty
@l1b3rty 我找不到任何文件保证getAllgetAllKeys的顺序是相同的。此外,由于它们在不同的时间被调用并且都是异步的,甚至数据库本身可能会在此期间发生变化。所以我认为,游标是最可靠的,并且实际上建议将其用作迭代器 - TheMechanic

1

或者您可以使用getAllKeys,然后使用事务获取每个键的值。

const getAll = (db, store) => new Promise((res, rej) => {
  // Fetch keys
  const keysTr = db.transaction(store).objectStore(store).getAllKeys()
  keysTr.onsuccess = (event) => {
    const keys = event.target.result
    if (keys?.length) {
      // Start a new transaction for final result
      const valuesTr = db.transaction(store)
      const objStore = valuesTr.objectStore(store)

      const result = [] // { key, value }[]

      // Iterate over keys
      keys.forEach(key => {
        const tr = objStore.get(key)
        tr.onsuccess = e => {
          result.push({
            key,
            value: e.target.result
          })
        }
      })
      // Resolve `getAll` with final { key, value }[] result
      valuesTr.oncomplete = (event) => {
        res(result)
      }
      valuesTr.onerror = (event) => {
        rej(event)
      }
    }
    else
      res([])
  }
  keysTr.onerror = (event) => {
    rej(event)
  }
})

2
我知道,当时我试图避免这种“回调地狱”的开始。使用IDBCursors后,代码看起来好多了。 - TheMechanic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接