IndexedDB getting all data with keys
Asked Answered
S

2

19

Using the IndexedDB API we have these 2 methods: getAll() and getAllKeys() with an usage example below:

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);
};

The problem is getAll() seems to retrieve only the data in an array format, and getAllKeys() gets all the keys without the data. I could not find a method to get both keys and values.

  1. Isn't there a better way of getting the data and the keys with one call, like it is stored?

  2. If not, is there a nicer way I could do this without making the code too confusing with multiple asynchronous calls happening?

Sopping answered 21/12, 2017 at 19:29 Comment(4)
Ummm, not really sure what to make of this question. Rather unclear, and answering it yourself isn't clear. Or why it was upvoted. But you can use getAll and just access the properties of each object...Wichman
@Wichman I've answered myself after finding a solution for my problem. To clarify it: sure you can access the properties of all objects with getAll(), but not the object's key stored in the IndexedDB table. The table storage has the content stored as a list of key: object pairs. getAll() gives me only the objects, getAllKeys() gives me only the keys. I wanted a method to retrieve me both key and object (or data) without multiple async calls.Sopping
Use inline keys and getAllWichman
Just came across this and found that Mechanic's solution is well suited. Inlining keys is rather bad practice, it is data duplication with a constant need to keep things in sync.Finnell
S
25

I was able to retrieve all values with their keys with one callback function using an IDBCursor like this:

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
   }
};
Sopping answered 21/12, 2017 at 20:3 Comment(2)
In my opinion, a better solution is to call getAllKeys and getAll separatly and using the fact that the results are ordered in the same way. The nth value from getAll matches the nth key from getAllKeysAholla
@Aholla I couldn't find any documentation that guarantees the order of getAll and getAllKeys to be the same. Besides, since they're called at different times and are both asynchronous, even the database itself might change in the meantime. So the way I see it, cursors are the most reliable and actually recommended to be used as iterators.Sopping
J
1

Alternatively you can use getAllKeys, followed by a transaction to fetch the values for each key.

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)
  }
})
Juicy answered 30/9, 2021 at 18:47 Comment(1)
I know, back then I was trying to avoid this beginning of a "callback hell". The code looks much better with IDBCursors.Sopping

© 2022 - 2024 — McMap. All rights reserved.