KeyPath是声明对象存储中主键来源的路径,用于从对象提取key值而非实现唯一性;唯一性由KeyPath配合非autoIncrement模式下的主键约束保障。

在HTML5的IndexedDB中,KeyPath不是用来“定义数据路径实现唯一性标识”的通用机制,而是用于声明对象存储(Object Store)中哪一属性(或嵌套属性)作为记录的主键(key)。它的核心作用是**从待存对象中提取主键值**,而非主动“实现唯一性”——唯一性由是否启用 autoIncrement 和主键约束共同决定。
KeyPath 的本质:主键来源声明
KeyPath 是一个字符串(如 "id")或数组(如 ["user", "profile", "uid"]),告诉 IndexedDB:“请从要添加的对象里,按这个路径取值,作为这条记录的 key”。它本身不生成、不校验、也不强制唯一;唯一性由以下规则保障:
- 若指定了 KeyPath 且未开启
autoIncrement: true,则每条记录必须提供该路径对应的有效值(不能为undefined或null),且重复 key 会抛出ConstraintError; - 若开启了
autoIncrement: true,KeyPath 就被忽略(系统自动生成递增数字 key),此时无法指定自定义主键; - KeyPath 支持点号路径(
"name"、"address.city")或数组路径(["a", "b", "c"]),用于访问嵌套对象属性。
常见 KeyPath 使用方式
创建 object store 时通过 createObjectStore 的 keyPath 选项设置:
const db = await openDB('myDB', 1, {
upgrade(db) {
// ✅ 使用字符串 KeyPath:主键来自对象的 id 字段
const store = db.createObjectStore('users', { keyPath: 'id' });
// ✅ 使用嵌套 KeyPath:主键来自 user.profile.uid
const store2 = db.createObjectStore('profiles', { keyPath: 'user.profile.uid' });
// ✅ 使用数组 KeyPath(等价于 'a.b.c')
const store3 = db.createObjectStore('logs', { keyPath: ['meta', 'trace', 'id'] });
}
});
插入数据时,对象必须包含对应路径的值:
-
store.add({ id: 101, name: 'Alice' })→ key =101; -
store2.add({ user: { profile: { uid: 'u-789' } } })→ key ='u-789'; -
store3.add({ meta: { trace: { id: 't-abc' } } })→ key ='t-abc'。
KeyPath 与唯一性的真实关系
IndexedDB 对主键有天然唯一性约束,但 KeyPath 本身不“实现”它——它是**触发该约束的前提条件之一**:
- 没有 KeyPath 且未开启 autoIncrement → 必须显式传入 key(如
store.add(obj, key)),重复 key 报错; - 有 KeyPath 且未开启 autoIncrement → 系统自动从对象提取 key,重复值仍报
ConstraintError; - KeyPath 不保证字段存在或类型合法:若对象无该路径属性,操作直接失败(
DataError); - 如需业务级唯一校验(如邮箱唯一),需在应用层检查或结合 index(如用
createIndex('by-email', 'email', { unique: true }))。
避坑提醒
- KeyPath 不能是空字符串、
null或包含数组索引(如"list.0.name"); - 修改已存在的 object store 的 keyPath 不被允许(版本升级时只能新建 store);
- 使用嵌套 KeyPath 时,中间层级必须是对象,否则取值为
undefined→ 导致DataError; - 避免用易变字段(如
updatedAt)作 KeyPath,会导致主键冲突或无法更新。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











