Reference

Indexes, ranges & cursors

Compressed map of secondary lookups. Pair with Lesson 4.

Create (upgrade only)

store.createIndex("by_project", "projectId", {
  unique: false,   // default
  multiEntry: false
});
// compound: store.createIndex("by_proj_time", ["projectId", "updatedAt"]);

Query

const index = tx.objectStore("notes").index("by_project");
index.get(key);
index.getAll(keyOrRange);
index.count(keyOrRange);
index.openCursor(keyOrRange);
index.openKeyCursor(keyOrRange);

IDBKeyRange

IDBKeyRange.only(x)
IDBKeyRange.lowerBound(x, open?)
IDBKeyRange.upperBound(x, open?)
IDBKeyRange.bound(lo, hi, lowerOpen?, upperOpen?)

Cursor loop

req.onsuccess = () => {
  const cursor = req.result;
  if (!cursor) return;
  // cursor.key, cursor.primaryKey, cursor.value
  cursor.continue();
};
Pick tool

Modest bounded results → get/getAll. Large or early-exit → cursor. Keys only → openKeyCursor.

Cost

Each index is write overhead + a versioned schema change. Plan the lookups you need; don’t spray indexes “just in case.”