Skip to content

IndexedDB - 索引

IndexedDB - 使用索引提升数据检索效率

Section titled “IndexedDB - 使用索引提升数据检索效率”

想象一下,一个对象存储区就像一本书。从头到尾地阅读来查找特定信息会很慢,尤其是对于一本大书。索引就像书末的索引:它提供了一种快速查找信息的方法。你可以查询索引,而不是扫描整个存储区,从而根据特定属性快速找到所需的记录。

索引是在对象存储区上创建的,它允许你使用存储对象的属性而不是仅仅使用它们的主键来获取数据。这对于高效查询至关重要。

索引与对象存储区一样,只能在 versionchange 事务中创建,这种事务发生在你以新的版本号打开数据库时,在 onupgradeneeded 事件处理程序内部。你可以在对象存储区实例上使用 createIndex() 方法。

// 在 onupgradeneeded 事件处理程序中
const store = db.createObjectStore('bots', { keyPath: 'id' });
const branchIndex = store.createIndex('branch_idx', 'branch', { unique: false });

createIndex 方法接受三个参数:

  • indexName (string): 在对象存储区中索引的唯一名称(例如,‘branch_idx’)。
  • keyPath (string | string[]): 存储对象上索引将用于查找的属性(或复合索引的多个属性)(例如,‘branch’)。
  • options (object, optional): 用于配置索引行为的对象:
  • unique (boolean): 如果为 true,数据库会强制要求没有两个对象的索引属性具有相同的值。默认为 false。
  • multiEntry (boolean): 如果 keyPath 指向一个数组,设置 multiEntry: true 会为数组中的每个元素创建一个索引条目。这对于实现标签或类别非常强大。默认为 false。

此示例演示了创建数据库、添加索引、填充数据,然后使用索引高效检索特定记录。我们将使用现代的 async/await 结构来编写更清晰的代码。请注意,我们不使用 document.write;而是将结果记录到浏览器的开发者控制台,这是标准做法。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>IndexedDB 索引示例</title>
</head>
<body>
<h1>IndexedDB 索引示例</h1>
<p>请查看浏览器的开发者控制台输出。</p>
<script>
const DB_NAME = 'BotDatabase';
const DB_VERSION = 1;
const STORE_NAME = 'bots';
const BRANCH_INDEX = 'branch_idx';
async function runDemo() {
// 1. 打开数据库连接
const request = indexedDB.open(DB_NAME, DB_VERSION);
request.onerror = (event) => {
console.error(`数据库错误: ${event.target.error}`);
};
request.onupgradeneeded = (event) => {
const db = event.target.result;
console.log('正在运行 onupgradeneeded...');
// 如果对象存储区不存在,则创建它
if (!db.objectStoreNames.contains(STORE_NAME)) {
const store = db.createObjectStore(STORE_NAME, { keyPath: 'id' });
// 在 'branch' 属性上创建索引
store.createIndex(BRANCH_INDEX, 'branch', { unique: false });
console.log('对象存储区和索引已创建。');
}
};
request.onsuccess = async (event) => {
const db = event.target.result;
console.log('数据库已成功打开。');
try {
// 2. 在 'readwrite' 事务中填充数据
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' },
];
// 使用 Promise.all 等待所有 'put' 操作完成
await Promise.all(bots.map(bot => storeWrite.put(bot)));
console.log('数据已填充。');
await txWrite.done; // 等待事务完成
// 3. 在 'readonly' 事务中使用索引查询数据
const txRead = db.transaction(STORE_NAME, 'readonly');
const storeRead = txRead.objectStore(STORE_NAME);
const branchIndex = storeRead.index(BRANCH_INDEX);
// 获取 'IT' 分支中的所有机器人
const itBotsRequest = branchIndex.getAll('IT');
itBotsRequest.onsuccess = () => {
console.log("查询结果: 'IT' 分支中的所有机器人:", itBotsRequest.result);
};
// 获取 'EEE' 分支中的单个机器人
const eeeBotRequest = branchIndex.get('EEE');
eeeBotRequest.onsuccess = () => {
console.log("查询结果: 'EEE' 分支中的单个机器人:", eeeBotRequest.result);
};
await txRead.done;
} catch (err) {
console.error('事务期间发生错误:', err);
} finally {
// 4. 关闭数据库连接
db.close();
console.log('数据库连接已关闭。');
}
};
}
runDemo();
</script>
</body>
</html>

当你运行上述 HTML 文件时,打开浏览器的开发者控制台。你应该看到类似以下的输出:

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.