IndexedDB - 对象存储
IndexedDB: 对象存储
Section titled “IndexedDB: 对象存储”对象存储(Object Store)是 IndexedDB 数据库中核心的数据容器,类似于传统 SQL 数据库中的“表”。单个数据库可以包含多个对象存储,每个对象存储都设计用于保存特定类型的 JavaScript 对象。本章将详细介绍如何创建、定义键以及管理对象存储。
创建对象存储
Section titled “创建对象存储”对象存储只能在 onupgradeneeded 事件处理程序中创建或修改。这种设计确保了所有模式(schema)修改都以受控的、版本化的方式进行。你可以使用 IDBDatabase.createObjectStore() 方法创建新的存储。
db.createObjectStore(storeName, options);storeName: 一个字符串,用于命名对象存储。options: 一个可选对象,用于配置主键。两个主要属性是keyPath和autoIncrement。
对象存储中的每条记录都必须有一个唯一键来标识它。IndexedDB 提供了两种主要方式来管理这些主键:
- 内联键(Key Path): 键是所存储对象的一个属性。你使用
keyPath选项指定此属性。例如,如果你存储用户对象,你可以使用email或userId属性作为键路径:{ keyPath: 'userId' }。 - 外联键(键生成器): 键是单独生成的,并与值一起存储。通过将
autoIncrement选项设置为true,你可以让 IndexedDB 为每个新对象自动生成一个递增的整数键。当你的对象没有自然唯一的属性时,这非常有用。
你可以同时使用 keyPath 和 autoIncrement。这对于为对象的特定属性分配唯一的自增 ID 非常有用。
示例:创建带有键路径的对象存储
Section titled “示例:创建带有键路径的对象存储”const request = indexedDB.open("CustomerDB", 1);
request.onupgradeneeded = (event) => { const db = event.target.result;
// 创建一个“customers”存储,其中每个对象的“email”属性作为主键。 const store = db.createObjectStore("customers", { keyPath: "email" });
console.log("'customers' object store created successfully.");};示例:创建带有自增键的对象存储
Section titled “示例:创建带有自增键的对象存储”const request = indexedDB.open("TaskDB", 1);
request.onupgradeneeded = (event) => { const db = event.target.result;
// 创建一个带有自增整数键的“tasks”存储。 // 键将独立于任务对象存储。 const store = db.createObjectStore("tasks", { autoIncrement: true });
// 我们也可以将它们结合使用。 // 这将创建一个“logs”存储,其中每个日志对象都会获得一个“id”属性, // 该属性会自动分配一个递增的数字。 const logStore = db.createObjectStore("logs", { keyPath: 'id', autoIncrement: true });
console.log("'tasks' and 'logs' object stores created.");};为高效查询定义索引
Section titled “为高效查询定义索引”虽然主键允许你高效地检索单个记录,但索引可以根据对象的其他属性实现快速查找。索引就像是数据的独立、排序视图。你可以在对象存储实例上使用 createIndex() 方法创建索引,同样是在 onupgradeneeded 事件中。
objectStore.createIndex(indexName, keyPath, options);indexName: 索引的名称。keyPath: 存储对象中用于排序和查找的属性。这也可以是用于复合索引的数组。options: 包含配置属性的可选对象,例如unique(确保索引中的所有值都是唯一的)和multiEntry(用于索引数组值)。
示例:创建索引和填充初始数据
Section titled “示例:创建索引和填充初始数据”此示例设置了一个 products 存储,并在 category 和 price 上创建了索引。它还展示了如何在模式创建后立即添加初始数据。
const request = indexedDB.open("StoreDB", 1);
request.onupgradeneeded = (event) => { const db = event.target.result;
// 创建对象存储 const store = db.createObjectStore("products", { keyPath: "id" });
// 在“category”属性上创建索引 store.createIndex("by_category", "category", { unique: false });
// 在“price”属性上创建索引 store.createIndex("by_price", "price", { unique: false });
console.log('Object store and indexes are ready.');
// onupgradeneeded 的事务仍然处于活动状态, // 所以我们可以在这里添加初始数据。 const initialProducts = [ { id: 'p1', name: 'Modern JavaScript', category: 'books', price: 29.99 }, { id: 'p2', name: 'Web Development', category: 'books', price: 39.99 }, { id: 'p3', name: 'Mechanical Keyboard', category: 'electronics', price: 150.00 } ];
// 要添加数据,我们需要通过事务再次访问存储 const productStore = event.target.transaction.objectStore('products'); initialProducts.forEach(product => { productStore.add(product); }); console.log('Initial products seeded.');};删除对象存储
Section titled “删除对象存储”如果不再需要某个对象存储,你可以使用 db.deleteObjectStore() 方法删除它。与创建类似,这也必须在 onupgradeneeded 事件中完成,这意味着你必须使用新的版本号打开数据库。
示例:删除对象存储
Section titled “示例:删除对象存储”// 假设“StoreDB”当前版本为 1 且包含一个“obsoleteStore”。// 要删除它,我们需要使用更高的版本号打开数据库。const request = indexedDB.open("StoreDB", 2);
request.onupgradeneeded = (event) => { const db = event.target.result;
// 在尝试删除之前,检查存储是否存在 if (db.objectStoreNames.contains('obsoleteStore')) { db.deleteObjectStore("obsoleteStore"); console.log("'obsoleteStore' has been deleted."); }};