How to use IndexedDB? Guide on Complete CRUD Operations and Best Practices

IndexedDB is a low-level API for client-side storage of significant amounts of structured data, including files/blobs. It’s a powerful way to store and retrieve data in a user’s browser, offering more storage capacity than localStorage and providing asynchronous access to data.

This guide will walk you through the basics of using IndexedDB, including how to perform Create, Read, Update, and Delete (CRUD) operations.

How to use IndexedDB? Guide on Complete CRUD Operations and Best Practices
How to use IndexedDB? Guide on Complete CRUD Operations and Best Practices

Table of Contents

1. Introduction to IndexedDB

2. Basic Concepts

3. Setting Up IndexedDB

4. CRUD Operations

5. Error Handling

6. Best Practices

7. Conclusion

Introduction to IndexedDB

What is IndexedDB?

IndexedDB is a NoSQL database built into modern browsers, allowing you to store significant amounts of data on the client side. Unlike localStorage, which stores data as simple key-value pairs and is synchronous, IndexedDB stores data in object stores and operates asynchronously, preventing UI blocking.

Why Use IndexedDB?

  • Storage Capacity: IndexedDB can store much more data than localStorage.
  • Structured Data: It allows storing complex objects.
  • Asynchronous: Non-blocking operations enhance performance.
  • Transactions: Provides ACID-compliant transactions for data integrity.
  • Indexes: Supports indexing to improve query performance.

Browser Support

IndexedDB is supported in all modern browsers:

  • Chrome
  • Firefox
  • Safari
  • Edge
  • Opera

Basic Concepts

Before diving into code, it’s essential to understand some fundamental concepts:

  • Database: The top-level container. You open a connection to a database.
  • Object Store: Similar to a table in SQL databases, it holds records.
  • Record: An object representing the data you store.
  • Key: A unique identifier for a record within an object store.
  • Transaction: All read/write operations occur within transactions.
  • Index: Allows you to query data efficiently based on properties.

Setting Up IndexedDB

Opening a Database

To interact with IndexedDB, you first need to open a connection to the database.

let db;
const request = indexedDB.open('MyTestDatabase', 1);

request.onupgradeneeded = function(event) {
  db = event.target.result;
  // Create an object store
  const objectStore = db.createObjectStore('customers', { keyPath: 'id', autoIncrement: true });
  // Create an index to search customers by name
  objectStore.createIndex('name', 'name', { unique: false });
};

request.onsuccess = function(event) {
  db = event.target.result;
  console.log('Database opened successfully');
};

request.onerror = function(event) {
  console.error('Database error:', event.target.errorCode);
};

Explanation:

  • indexedDB.open(): Opens a connection to the database.
  • onupgradeneeded: Triggered when the database is created or a higher version number is passed.
  • createObjectStore(): Creates an object store (like a table).
  • createIndex(): Creates an index on a specified property.

CRUD Operations

Create

You can add data to the object store using the add() or put() methods.

function addCustomer(customer) {
  const transaction = db.transaction(['customers'], 'readwrite');
  const objectStore = transaction.objectStore('customers');
  const request = objectStore.add(customer);

  request.onsuccess = function() {
    console.log('Customer added:', customer);
  };

  request.onerror = function(event) {
    console.error('Add failed:', event.target.errorCode);
  };
}

// Usage
addCustomer({ name: 'John Doe', email: '[email protected]' });

Explanation:

  • transaction(): Creates a transaction for specified object stores.
  • objectStore(): Accesses an object store within the transaction.
  • add(): Adds a new record to the object store.

Read

Read a Single Record

function getCustomer(id) {
  const transaction = db.transaction(['customers']);
  const objectStore = transaction.objectStore('customers');
  const request = objectStore.get(id);

  request.onsuccess = function(event) {
    if (request.result) {
      console.log('Customer:', request.result);
    } else {
      console.log('Customer not found');
    }
  };

  request.onerror = function(event) {
    console.error('Get failed:', event.target.errorCode);
  };
}

// Usage
getCustomer(1);

Read All Records

function getAllCustomers() {
  const transaction = db.transaction(['customers']);
  const objectStore = transaction.objectStore('customers');
  const request = objectStore.getAll();

  request.onsuccess = function(event) {
    console.log('All customers:', request.result);
  };

  request.onerror = function(event) {
    console.error('GetAll failed:', event.target.errorCode);
  };
}

// Usage
getAllCustomers();

Explanation:

  • get(): Retrieves a record by key.
  • getAll(): Retrieves all records from the object store.

Using Cursors

Cursors allow you to iterate over records.

function iterateCustomers() {
  const transaction = db.transaction(['customers']);
  const objectStore = transaction.objectStore('customers');
  const request = objectStore.openCursor();

  request.onsuccess = function(event) {
    const cursor = event.target.result;
    if (cursor) {
      console.log('Customer:', cursor.value);
      cursor.continue();
    } else {
      console.log('No more entries');
    }
  };

  request.onerror = function(event) {
    console.error('Cursor failed:', event.target.errorCode);
  };
}

// Usage
iterateCustomers();

Update

To update a record, you can use the put() method.

function updateCustomer(id, updatedData) {
  const transaction = db.transaction(['customers'], 'readwrite');
  const objectStore = transaction.objectStore('customers');
  const request = objectStore.get(id);

  request.onsuccess = function(event) {
    const data = request.result;
    if (data) {
      // Update the fields
      Object.assign(data, updatedData);
      const updateRequest = objectStore.put(data);

      updateRequest.onsuccess = function() {
        console.log('Customer updated:', data);
      };

      updateRequest.onerror = function(event) {
        console.error('Update failed:', event.target.errorCode);
      };
    } else {
      console.log('Customer not found');
    }
  };

  request.onerror = function(event) {
    console.error('Get failed:', event.target.errorCode);
  };
}

// Usage
updateCustomer(1, { email: '[email protected]' });

Explanation:

  • get(): Retrieve the existing record.
  • Object.assign(): Merge updated data into the existing record.
  • put(): Updates the record.

Delete

To delete a record, use the delete() method.

function deleteCustomer(id) {
  const transaction = db.transaction(['customers'], 'readwrite');
  const objectStore = transaction.objectStore('customers');
  const request = objectStore.delete(id);

  request.onsuccess = function() {
    console.log('Customer deleted:', id);
  };

  request.onerror = function(event) {
    console.error('Delete failed:', event.target.errorCode);
  };
}

// Usage
deleteCustomer(1);

Explanation:

  • delete(): Removes a record by key.

Error Handling

Always include error handlers to catch any issues.

  • request.onerror: Handles errors for individual requests.
  • transaction.onerror: Handles errors for the entire transaction.

Example:

transaction.onerror = function(event) {
  console.error('Transaction failed:', event.target.errorCode);
};

Best Practices

  • Versioning: Increment the database version number to trigger onupgradeneeded for schema changes.
  • Indexes: Use indexes to optimize query performance.
  • Transactions: Group multiple operations in a single transaction when possible.
  • Promises: Consider wrapping IndexedDB calls in Promises for cleaner asynchronous code.
  • Error Handling: Always include error handlers for robustness.
  • Feature Detection: Check if the browser supports IndexedDB.

Example of Feature Detection:

if (!('indexedDB' in window)) {
  console.error('This browser doesn\'t support IndexedDB');
}

Conclusion

IndexedDB is a robust solution for client-side storage of large amounts of structured data. By understanding its core concepts and following best practices, you can effectively implement CRUD operations in your web applications.

References:

Learn More: AI and Machine Learning

How to Run MongoDB in Docker- Step by Step Guide

Automated Log Cleanup for GBase 8a: A Step-by-Step Guide

How to Set Up a Self-Hosted PostgreSQL Database with SSL Support

7 Best Open-Source AI Coding Tools Every Developer Should Know

Build Your Own AI-Powered Search Engine with SWIRL

Top 8 Open Source MLOps Tools for Production

Leave a Comment

Comments

No comments yet. Why don’t you start the discussion?

    Comments