Skip to content

IndexedDB - Indexes

IndexedDB - Supercharging Data Retrieval with Indexes

Section titled “IndexedDB - Supercharging Data Retrieval with Indexes”

Imagine an object store is like a book. Finding a specific piece of information by reading from start to finish would be slow, especially for a large book. An index is like the index at the back of the book: it provides a fast way to look up information. Instead of scanning the entire store, you can query the index to quickly find the records you need based on a specific property.

Indexes are created on an object store and allow you to fetch data using a property of the stored objects, rather than just their primary key. This is essential for efficient querying.

Indexes, like object stores, can only be created within a versionchange transaction, which occurs inside the onupgradeneeded event handler when you open a database with a new version number. You use the createIndex() method on an object store instance.

// Inside the onupgradeneeded event handler
const store = db.createObjectStore('bots', { keyPath: 'id' });
const branchIndex = store.createIndex('branch_idx', 'branch', { unique: false });

The createIndex method accepts three arguments:

  • indexName (string): A unique name for the index within the object store (e.g., ‘branch_idx’).
  • keyPath (string | string[]): The property (or properties for a compound index) on your stored objects that the index will use for lookups (e.g., ‘branch’).
  • options (object, optional): An object to configure the index’s behavior:
  • unique (boolean): If true, the database enforces that no two objects can have the same value for the indexed property. Defaults to false.
  • multiEntry (boolean): If the keyPath points to an array, setting multiEntry: true creates an index entry for each element in the array. This is powerful for implementing tags or categories. Defaults to false.

This example demonstrates creating a database, adding an index, populating it with data, and then using the index to efficiently retrieve specific records. We’ll use a modern async/await structure for cleaner code. Notice we’re not using document.write; instead, we log results to the browser’s developer console, which is standard practice.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>IndexedDB Indexes Example</title>
</head>
<body>
<h1>IndexedDB Indexes Example</h1>
<p>Check the browser's developer console for output.</p>
<script>
const DB_NAME = 'BotDatabase';
const DB_VERSION = 1;
const STORE_NAME = 'bots';
const BRANCH_INDEX = 'branch_idx';
async function runDemo() {
// 1. Open the database connection
const request = indexedDB.open(DB_NAME, DB_VERSION);
request.onerror = (event) => {
console.error(`Database error: ${event.target.error}`);
};
request.onupgradeneeded = (event) => {
const db = event.target.result;
console.log('Running onupgradeneeded...');
// Create an object store if it doesn't exist
if (!db.objectStoreNames.contains(STORE_NAME)) {
const store = db.createObjectStore(STORE_NAME, { keyPath: 'id' });
// Create an index on the 'branch' property
store.createIndex(BRANCH_INDEX, 'branch', { unique: false });
console.log('Object store and index created.');
}
};
request.onsuccess = async (event) => {
const db = event.target.result;
console.log('Database opened successfully.');
try {
// 2. Populate data in a 'readwrite' transaction
const txWrite = db.transaction(STORE_NAME, 'readwrite');
const storeWrite = txWrite.objectStore(STORE_NAME);
const bots = [
{ id: 1, name: 'Jason', branch: 'IT' },
{ id: 2, name: 'Praneeth', branch: 'CSE' },
{ id: 3, name: 'Palli', branch: 'EEE' },
{ id: 4, name: 'Abdul', branch: 'IT' },
{ id: 5, name: 'Deevana', branch: 'CSE' },
];
// Use Promise.all to wait for all 'put' operations to complete
await Promise.all(bots.map(bot => storeWrite.put(bot)));
console.log('Data populated.');
await txWrite.done; // Wait for the transaction to complete
// 3. Query data using the index in a 'readonly' transaction
const txRead = db.transaction(STORE_NAME, 'readonly');
const storeRead = txRead.objectStore(STORE_NAME);
const branchIndex = storeRead.index(BRANCH_INDEX);
// Get all bots in the 'IT' branch
const itBotsRequest = branchIndex.getAll('IT');
itBotsRequest.onsuccess = () => {
console.log("Query Result: All bots in 'IT' branch:", itBotsRequest.result);
};
// Get a single bot from the 'EEE' branch
const eeeBotRequest = branchIndex.get('EEE');
eeeBotRequest.onsuccess = () => {
console.log("Query Result: A single bot from 'EEE' branch:", eeeBotRequest.result);
};
await txRead.done;
} catch (err) {
console.error('An error occurred during transactions:', err);
} finally {
// 4. Close the database connection
db.close();
console.log('Database connection closed.');
}
};
}
runDemo();
</script>
</body>
</html>

When you run the above HTML file, open your browser’s developer console. You should see output similar to this:

Running onupgradeneeded...
Object store and index created.
Database opened successfully.
Data populated.
Query Result: All bots in 'IT' branch:
[
{ id: 1, name: 'Jason', branch: 'IT' },
{ id: 4, name: 'Abdul', branch: 'IT' }
]
Query Result: A single bot from 'EEE' branch:
{ id: 3, name: 'Palli', branch: 'EEE' }
Database connection closed.