IndexedDB - Ranges
IndexedDB: Querying Data Ranges with IDBKeyRange
Section titled “IndexedDB: Querying Data Ranges with IDBKeyRange”To move beyond fetching single records, you need to query for data within a specific range. For example, finding all emails received today, or all products priced between $50 and $100. IndexedDB provides the IDBKeyRange object for exactly this purpose.
An IDBKeyRange defines a continuous range of keys. You can use it with methods like getAll(), openCursor(), or count() to filter the results from an object store or an index.
Methods for Creating Key Ranges
Section titled “Methods for Creating Key Ranges”The IDBKeyRange object has several static methods to define different types of ranges:
| Method | Description | Example (Range) |
|---|---|---|
| IDBKeyRange.lowerBound(lower, [open]) | Matches all keys greater than or equal to lower. If open is true, it matches keys strictly greater than lower. | ≥ a or > a |
| IDBKeyRange.upperBound(upper, [open]) | Matches all keys less than or equal to upper. If open is true, it matches keys strictly less than upper. | ≤ b or < b |
| IDBKeyRange.bound(lower, upper, [lowerOpen], [upperOpen]) | Matches all keys between lower and upper. The open flags can be used to exclude the boundaries. | ≥ a && ≤ b |
| IDBKeyRange.only(value) | Matches only the key that is exactly equal to value. | = c |
Practical Examples
Section titled “Practical Examples”Here are some examples of how to apply these ranges to a products store with a price index.
// Find products with price >= 100const range1 = IDBKeyRange.lowerBound(100);const expensiveProducts = await db.getAllFromIndex('products', 'priceIdx', range1);
// Find products with price < 20 (exclusive)const range2 = IDBKeyRange.upperBound(20, true);const cheapProducts = await db.getAllFromIndex('products', 'priceIdx', range2);
// Find products with price between 50 and 150 (inclusive)const range3 = IDBKeyRange.bound(50, 150);const midRangeProducts = await db.getAllFromIndex('products', 'priceIdx', range3);
// Find all products with the exact price of 99.99const range4 = IDBKeyRange.only(99.99);const specificPriceProducts = await db.getAllFromIndex('products', 'priceIdx', range4);Complete Example: Querying by Date Range
Section titled “Complete Example: Querying by Date Range”A common use case is fetching records based on a date range. This example creates a logs store, adds entries with timestamps, and then queries for logs created within the last hour.
<!DOCTYPE html><html lang="en"><head> <title>IndexedDB Range Query Example</title></head><body> <h1>Check the console for output</h1> <script type="module"> import { openDB } from 'https://cdn.jsdelivr.net/npm/idb@7/build/index.js';
async function runDemo() { const db = await openDB('appLogsDB', 1, { upgrade(db) { const store = db.createObjectStore('logs', { autoIncrement: true }); store.createIndex('timestampIdx', 'timestamp'); }, });
const twoHoursAgo = new Date(); twoHoursAgo.setHours(twoHoursAgo.getHours() - 2); const thirtyMinsAgo = new Date(); thirtyMinsAgo.setMinutes(thirtyMinsAgo.getMinutes() - 30);
// Add some sample data const tx = db.transaction('logs', 'readwrite'); await Promise.all([ tx.store.add({ message: 'User logged in', timestamp: new Date() }), tx.store.add({ message: 'Data fetched from API', timestamp: thirtyMinsAgo }), tx.store.add({ message: 'Old session cleared', timestamp: twoHoursAgo }), ]); await tx.done;
// Query for logs from the last hour const oneHourAgo = new Date(); oneHourAgo.setHours(oneHourAgo.getHours() - 1);
const range = IDBKeyRange.lowerBound(oneHourAgo); const recentLogs = await db.getAllFromIndex('logs', 'timestampIdx', range);
console.log('Logs from the last hour:'); console.table(recentLogs); }
runDemo().catch(console.error); </script></body></html>Expected Output
Section titled “Expected Output”The console will display a table containing the two log entries from the last hour (‘User logged in’ and ‘Data fetched from API’), excluding the entry from two hours ago.