469
IndexedDB is a low-level API for storing structured data in the browser. It allows you to store large amounts of data and retrieve it efficiently using key-value pairs.
Unlike localStorage, IndexedDB is asynchronous and supports advanced features like transactions, indexing, and searching.
In this tutorial, you’ll learn:
- What is IndexedDB and its benefits.
- Setting up and creating a database.
- Performing CRUD (Create, Read, Update, Delete) operations.
- Using indexes for efficient data retrieval.
- Practical examples with IndexedDB.
1. What is IndexedDB?
IndexedDB is:
- Asynchronous: Operates without blocking the main thread.
- Persistent: Stores data even after the browser is closed.
- Structured: Supports objects, arrays, and complex data types.
- Powerful: Offers transactions, versioning, and indexing for fast lookups.
Use Cases:
- Offline web applications.
- Storing large datasets like user preferences, chat history, or product catalogs.
- Caching API responses.
2. Setting Up IndexedDB
Example 1: Creating a Database
// Open or create a database
const request = indexedDB.open("MyDatabase", 1);
// Handle success
request.onsuccess = function (event) {
console.log("Database opened successfully:", event.target.result);
};
// Handle errors
request.onerror = function (event) {
console.error("Database error:", event.target.error);
};
// Set up the database structure
request.onupgradeneeded = function (event) {
const db = event.target.result;
// Create an object store with a key path
const store = db.createObjectStore("Users", { keyPath: "id" });
// Create indexes for quick lookups
store.createIndex("name", "name", { unique: false });
store.createIndex("email", "email", { unique: true });
console.log("Object store and indexes created.");
};
Explanation:
- indexedDB.open(“MyDatabase”, version): Opens or creates a database with the specified version.
- onupgradeneeded: Triggered if the database needs a new schema.
3. Performing CRUD Operations
Example 2: Adding Data to IndexedDB
const request = indexedDB.open("MyDatabase", 1);
request.onsuccess = function (event) {
const db = event.target.result;
// Start a transaction
const transaction = db.transaction("Users", "readwrite");
const store = transaction.objectStore("Users");
// Add data
store.add({ id: 1, name: "John Doe", email: "john@example.com" });
store.add({ id: 2, name: "Jane Smith", email: "jane@example.com" });
transaction.oncomplete = function () {
console.log("Data added successfully.");
};
transaction.onerror = function (event) {
console.error("Transaction error:", event.target.error);
};
};
Explanation:
- transaction.objectStore(name): Accesses the specified object store.
- store.add(data): Adds data to the store.
Example 3: Reading Data from IndexedDB
const request = indexedDB.open("MyDatabase", 1);
request.onsuccess = function (event) {
const db = event.target.result;
// Start a transaction
const transaction = db.transaction("Users", "readonly");
const store = transaction.objectStore("Users");
// Get a specific item by key
const getRequest = store.get(1);
getRequest.onsuccess = function (event) {
console.log("Retrieved data:", event.target.result);
};
getRequest.onerror = function (event) {
console.error("Get request error:", event.target.error);
};
};
Explanation:
- store.get(key): Retrieves an item by its key.
Example 4: Updating Data in IndexedDB
const request = indexedDB.open("MyDatabase", 1);
request.onsuccess = function (event) {
const db = event.target.result;
// Start a transaction
const transaction = db.transaction("Users", "readwrite");
const store = transaction.objectStore("Users");
// Update an existing item
const updateRequest = store.put({ id: 1, name: "John Doe", email: "john.doe@example.com" });
updateRequest.onsuccess = function () {
console.log("Data updated successfully.");
};
updateRequest.onerror = function (event) {
console.error("Update error:", event.target.error);
};
};
Explanation:
- store.put(data): Updates or adds data if the key already exists.
Example 5: Deleting Data from IndexedDB
const request = indexedDB.open("MyDatabase", 1);
request.onsuccess = function (event) {
const db = event.target.result;
// Start a transaction
const transaction = db.transaction("Users", "readwrite");
const store = transaction.objectStore("Users");
// Delete an item by key
const deleteRequest = store.delete(1);
deleteRequest.onsuccess = function () {
console.log("Data deleted successfully.");
};
deleteRequest.onerror = function (event) {
console.error("Delete error:", event.target.error);
};
};
Explanation:
- store.delete(key): Deletes an item by its key.
4. Using Indexes
Indexes allow you to query data efficiently.
Example 6: Querying Data by Index
const request = indexedDB.open("MyDatabase", 1);
request.onsuccess = function (event) {
const db = event.target.result;
// Start a transaction
const transaction = db.transaction("Users", "readonly");
const store = transaction.objectStore("Users");
const index = store.index("email");
// Get an item by index
const indexRequest = index.get("jane@example.com");
indexRequest.onsuccess = function (event) {
console.log("Queried data:", event.target.result);
};
indexRequest.onerror = function (event) {
console.error("Index query error:", event.target.error);
};
};
Explanation:
- store.index(name): Accesses an index.
- index.get(value): Retrieves data based on an indexed value.
5. Deleting an Object Store
To delete an object store, update the database schema.
Example 7: Delete an Object Store
const request = indexedDB.open("MyDatabase", 2);
request.onupgradeneeded = function (event) {
const db = event.target.result;
// Delete an existing object store
if (db.objectStoreNames.contains("Users")) {
db.deleteObjectStore("Users");
console.log("Object store deleted.");
}
};
6. Practical Application: Todo App
Example 8: A Simple Todo App with IndexedDB
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>IndexedDB Todo App</title>
</head>
<body>
<h1>Todo App</h1>
<input type="text" id="todoInput" placeholder="Enter a todo">
<button id="addTodo">Add Todo</button>
<ul id="todoList"></ul>
<script src="todoApp.js"></script>
</body>
</html>
JavaScript (todoApp.js)
const request = indexedDB.open("TodoDB", 1);
request.onupgradeneeded = function (event) {
const db = event.target.result;
db.createObjectStore("Todos", { keyPath: "id", autoIncrement: true });
};
request.onsuccess = function (event) {
const db = event.target.result;
const addTodo = () => {
const todoInput = document.getElementById("todoInput");
const transaction = db.transaction("Todos", "readwrite");
const store = transaction.objectStore("Todos");
store.add({ text: todoInput.value });
todoInput.value = "";
displayTodos();
};
const displayTodos = () => {
const transaction = db.transaction("Todos", "readonly");
const store = transaction.objectStore("Todos");
const todoList = document.getElementById("todoList");
todoList.innerHTML = "";
store.openCursor().onsuccess = function (event) {
const cursor = event.target.result;
if (cursor) {
const li = document.createElement("li");
li.textContent = cursor.value.text;
todoList.appendChild(li);
cursor.continue();
}
};
};
document.getElementById("addTodo").addEventListener("click", addTodo);
displayTodos();
};
7. Best Practices
- Use Transactions: Always use transactions for consistency.
- Handle Errors: Provide meaningful error messages.
- Schema Versioning: Use the version parameter to manage schema changes.
- Browser Compatibility: Test your application across different browsers.
8. Conclusion
In this tutorial, you learned:
- How to set up and use IndexedDB.
- CRUD operations and using indexes for efficient queries.
- How to apply IndexedDB in a practical example like a Todo App.
IndexedDB is a powerful tool for building offline-capable and data-intensive web applications.
