Skip to content

Creating and Querying Indexes

Every IndexedDB object store is keyed by its primary key (the keyPath or an auto-incremented id). That is efficient for lookups by primary key, but if you want to query by a different field — for example, find all contacts by their name — you need an index.

An index is a secondary sorted structure that maps a chosen field’s value back to the record’s primary key. Once created, you can call get() or getAll() on the index exactly as you would on the store itself.

Indexes must be created (or deleted) inside the onupgradeneeded callback. You cannot add an index to an existing store outside of an upgrade transaction.

const request = indexedDB.open('mydb', 1);
request.onupgradeneeded = (event) => {
const db = event.target.result;
// Create the object store
const store = db.createObjectStore('contacts', { keyPath: 'id' });
// Create an index on the 'name' field
store.createIndex('by_name', 'name', { unique: false });
};

createIndex(name, keyPath, options) parameters

Section titled “createIndex(name, keyPath, options) parameters”
ParameterPurpose
nameThe index name you will use to retrieve it later with store.index(name)
keyPathThe property path on each record to index (e.g. 'name', 'address.city')
uniqueIf true, the store rejects records whose indexed value duplicates an existing one
multiEntryIf true and the indexed property is an array, each array element gets its own entry in the index

After the upgrade, open the index from a normal read/write transaction with store.index('by_name'), then call get(value) for a single record or getAll(value) for all matching records.

const tx = db.transaction('contacts', 'readonly');
const store = tx.objectStore('contacts');
const nameIndex = store.index('by_name');
// Single match
const getReq = nameIndex.get('Alice');
getReq.onsuccess = () => console.log(getReq.result); // { id: 1, name: 'Alice', ... }
// All records (no filter → returns every record sorted by index key)
const getAllReq = nameIndex.getAll();
getAllReq.onsuccess = () => console.log(getAllReq.result);

Passing a value to getAll(value) filters to records whose indexed field equals that value. Passing no argument (or undefined) returns every record in the store, ordered by the index key.

// Enforce unique emails
store.createIndex('by_email', 'email', { unique: true });

With unique: true, any add() or put() that would create a duplicate indexed value throws a ConstraintError. Use this for fields like email addresses or usernames where duplicates are not allowed.

// Record: { id: 1, tags: ['js', 'idb', 'storage'] }
store.createIndex('by_tag', 'tags', { multiEntry: true });

With multiEntry: true, an array-valued field produces one index entry per element. You can then call index.getAll('idb') and the record above will be returned even though the value of tags is an array.

Browser Storage
Where must you call objectStore.createIndex() to successfully add an index?
What does setting { unique: true } on an index do?
You call nameIndex.getAll() with no arguments. What is returned?
A record has the field tags: ["js", "idb"]. Which createIndex option makes both "js" and "idb" individually searchable via index.getAll("js")?