在 Dexie table 中搜索数组中的键
Search Dexie table for a key in an array
如果我在indexedDB/Dexietable中有如下记录:
{
id: 1,
name: "foo",
children: [{id: 12, bar: "b"},
{id: 14, bar: "c"}]
}
每个 child ID 都是唯一的。也就是说,只有 1 条记录的 child 给定 id 为 14.
- 如何在 children 上设置索引,以便我可以搜索包含 ID 为 14 的 child 的记录?
- 然后我如何最有效地搜索包含 child 且键位于
anyOf([3, 7, 9])
中的多条记录
看起来像:
- 只有Indexable Types可以用于多条目索引
- Edge 仍然不支持 indexed-db 标准的多入口键!!!坦率地说可笑。
- 允许原始问题中描述的行为 has been suggested
考虑将父数据冗余存储在子对象中。例如。 table 中的一个对象看起来像:
{
"parent" : {
"id": 1,
"name": "foo",
},
"id": 12,
"bar": "a"
}
然后您可以在 id 上创建索引。或者,因为child id是object key,所以其实不需要创建索引,可以针对object store的key路径进行查询。
但是,您不能执行 IN
样式查询。因为 IN 本质上是 shorthand for id = 1 or id = 2 or id = 3
,这是一个联合,这是在 indexedDB 中做不到的。至少效率不高。在这种情况下,您需要做的是创建 3 个查询,每个查询一个,每个查询针对相同的索引(或对象存储的键路径),然后将结果合并到一个数组中。
IndexedDB 允许多条目索引,但仅限于简单数组,而不是 objects 的数组。但是你可以解决这个问题,方法是在一侧维护一个数组,其中包含所有包含的 id 和索引 属性 而不是:
{
id: 1,
name: "foo",
children: [{id: 12, bar: "b"},
{id: 14, bar: "c"}],
childrenIds: [12, 14]
}
// Dexie schema:
const db = new Dexie("db");
db.version(1).stores({
table: "++id, *childrenIds"
});
MultiEntry 索引适用于 Chromium、Firefox 和 Safari。 IE11 不支持,但即将推出的 Chromium-based Edge 浏览器会。
替代方法
另一种方法是以关系方式设计您的 table:
const db = new Dexie("relDB");
db.version(1).stores({
parents: "++id",
children: "++id, parentId"
});
Parent objects:
{
id: 1,
name: "foo",
}
Child objects:
{id: 12, bar: "b", parentId: 1}
{id: 14, bar: "c", parentId: 1}
然后,要根据一组 child 个 ID [12、14] 检索 parent,请对 children [=56= 使用 anyOf() 查询]:
const children = await db.children.where('id').anyOf([12, 14]).toArray();
const parentIds = new Set(children.map(child => child.parentId));
const parents = await db.parents.bulkGet([...parentIds]);
结论
我已经介绍了两种可选方法,它们都是解决您问题的有效方法。第一个选项是添加一个简单的 child ID 数组和使用 MultiEntry 索引的索引,另一个选项是将 children 放在单独的 table 中。如果您选择第二个选项,使用 dexie-relationships 插件查询包含 parents 的 children 或包含 parents 的查询也可能会有所帮助child含仁。
备注
我在 children 上索引 parentId
的原因是在关系模式中这样做是一个很好的做法,以便能够查询所有 children某些parent(此处不举例)。
如果我在indexedDB/Dexietable中有如下记录:
{
id: 1,
name: "foo",
children: [{id: 12, bar: "b"},
{id: 14, bar: "c"}]
}
每个 child ID 都是唯一的。也就是说,只有 1 条记录的 child 给定 id 为 14.
- 如何在 children 上设置索引,以便我可以搜索包含 ID 为 14 的 child 的记录?
- 然后我如何最有效地搜索包含 child 且键位于
anyOf([3, 7, 9])
中的多条记录
看起来像:
- 只有Indexable Types可以用于多条目索引
- Edge 仍然不支持 indexed-db 标准的多入口键!!!坦率地说可笑。
- 允许原始问题中描述的行为 has been suggested
考虑将父数据冗余存储在子对象中。例如。 table 中的一个对象看起来像:
{
"parent" : {
"id": 1,
"name": "foo",
},
"id": 12,
"bar": "a"
}
然后您可以在 id 上创建索引。或者,因为child id是object key,所以其实不需要创建索引,可以针对object store的key路径进行查询。
但是,您不能执行 IN
样式查询。因为 IN 本质上是 shorthand for id = 1 or id = 2 or id = 3
,这是一个联合,这是在 indexedDB 中做不到的。至少效率不高。在这种情况下,您需要做的是创建 3 个查询,每个查询一个,每个查询针对相同的索引(或对象存储的键路径),然后将结果合并到一个数组中。
IndexedDB 允许多条目索引,但仅限于简单数组,而不是 objects 的数组。但是你可以解决这个问题,方法是在一侧维护一个数组,其中包含所有包含的 id 和索引 属性 而不是:
{
id: 1,
name: "foo",
children: [{id: 12, bar: "b"},
{id: 14, bar: "c"}],
childrenIds: [12, 14]
}
// Dexie schema:
const db = new Dexie("db");
db.version(1).stores({
table: "++id, *childrenIds"
});
MultiEntry 索引适用于 Chromium、Firefox 和 Safari。 IE11 不支持,但即将推出的 Chromium-based Edge 浏览器会。
替代方法
另一种方法是以关系方式设计您的 table:
const db = new Dexie("relDB");
db.version(1).stores({
parents: "++id",
children: "++id, parentId"
});
Parent objects:
{
id: 1,
name: "foo",
}
Child objects:
{id: 12, bar: "b", parentId: 1}
{id: 14, bar: "c", parentId: 1}
然后,要根据一组 child 个 ID [12、14] 检索 parent,请对 children [=56= 使用 anyOf() 查询]:
const children = await db.children.where('id').anyOf([12, 14]).toArray();
const parentIds = new Set(children.map(child => child.parentId));
const parents = await db.parents.bulkGet([...parentIds]);
结论
我已经介绍了两种可选方法,它们都是解决您问题的有效方法。第一个选项是添加一个简单的 child ID 数组和使用 MultiEntry 索引的索引,另一个选项是将 children 放在单独的 table 中。如果您选择第二个选项,使用 dexie-relationships 插件查询包含 parents 的 children 或包含 parents 的查询也可能会有所帮助child含仁。
备注
我在 children 上索引 parentId
的原因是在关系模式中这样做是一个很好的做法,以便能够查询所有 children某些parent(此处不举例)。