Skip to content

IndexedDB - 搜索

作为一种结构化数据库,IndexedDB 提供了高效的数据搜索和检索机制。你可以根据主键查询记录,或者使用索引对对象的其他属性进行更复杂的查找。

检索数据最直接的方式是使用 get() 方法通过主键进行。对于更高级的查询,你可以使用 IDBKeyRange 对象来指定键的范围。

基于键的搜索主要方法有:

  • store.get(key):搜索与键匹配的第一个值。
  • store.getAll([query], [count]):搜索与可选查询(键或键范围)匹配的所有值,最多 count 个。
  • store.getKey(key):搜索与键匹配的第一个键。
  • store.getAllKeys([query], [count]):搜索与可选查询匹配的所有键,最多 count 个。
  • store.count([query]):获取与可选查询匹配的记录总数。
// 假设 'db' 是一个来自 'idb' 库的已打开的 IDBDatabase 实例
// 通过 ID(主键)获取单个产品
const product = await db.get('products', 'prod-123');
// 获取 ID 在 'prod-100' 和 'prod-200' 之间的所有产品
const keyRange = IDBKeyRange.bound('prod-100', 'prod-200');
const products = await db.getAll('products', keyRange);
// 只获取前 5 个产品键
const keys = await db.getAllKeys('products', null, 5);

要高效地按主键以外的属性进行搜索,你必须创建一个索引。索引根据指定属性维护一个指向对象的排序引用列表,从而实现快速查找。

索引只能在 openDB 的 upgrade 回调中创建。

objectStore.createIndex(indexName, keyPath, [options]);
  • indexName:索引的唯一名称。
  • keyPath:要索引的对象的属性路径(例如 'price' 或 'address.city')。
  • options:一个可选对象,包含配置属性:

unique: true:确保存储中没有两条记录可以拥有相同的索引键值。尝试添加重复项将导致错误。 multiEntry: true:如果 keyPath 解析为数组,则索引将为数组的每个成员添加一个条目。这非常适合实现标签或类别功能。

// 在 'upgrade' 回调中
const productsStore = db.createObjectStore('products', { keyPath: 'id' });
// 创建一个索引,用于按产品 'category' 搜索产品
productsStore.createIndex('categoryIdx', 'category', { unique: false });
// 使用 multiEntry 为标签创建索引
productsStore.createIndex('tagsIdx', 'tags', { multiEntry: true });

此示例演示如何设置一个包含 ‘products’ 存储和 ‘category’ 索引的数据库,添加数据,然后搜索 ‘electronics’ 类别中的所有产品。

<!DOCTYPE html>
<html lang="en">
<head>
<title>IndexedDB 搜索示例</title>
</head>
<body>
<h1>检查控制台输出</h1>
<script type="module">
import { openDB } from 'https://cdn.jsdelivr.net/npm/idb@7/build/index.js';
async function runDemo() {
const db = await openDB('shopDB', 1, {
upgrade(db) {
if (!db.objectStoreNames.contains('products')) {
const store = db.createObjectStore('products', { keyPath: 'id' });
store.createIndex('categoryIdx', 'category');
}
},
});
const tx = db.transaction('products', 'readwrite');
const store = tx.objectStore('products');
// 添加一些示例数据
await Promise.all([
store.put({ id: 'p1', name: 'Laptop', category: 'electronics' }),
store.put({ id: 'p2', name: 'T-Shirt', category: 'apparel' }),
store.put({ id: 'p3', name: 'Keyboard', category: 'electronics' }),
]);
await tx.done;
console.log('Database populated!');
// 现在,使用索引搜索所有 'electronics' 产品
const electronics = await db.getAllFromIndex('products', 'categoryIdx', 'electronics');
console.log('Electronics Products:', electronics);
console.table(electronics);
}
runDemo().catch(console.error);
</script>
</body>
</html>

预期输出(在浏览器控制台中)

Section titled “预期输出(在浏览器控制台中)”
Database populated!
Electronics Products: [ { id: 'p1', name: 'Laptop', category: 'electronics' }, { id: 'p3', name: 'Keyboard', category: 'electronics' } ]
(console.table output)
┌─────────┬──────┬───────────┬───────────────┐
│ (index) │ id │ name │ category │
├─────────┼──────┼───────────┼───────────────┤
│ 0 │ 'p1' │ 'Laptop' │ 'electronics' │
│ 1 │ 'p3' │ 'Keyboard'│ 'electronics' │
└─────────┴──────┴───────────┴───────────────┘