从缺少 属性 的 indexedDB 对象存储中删除对象的有效方法
An efficient way of removing objects from an indexedDB object store that are missing a property
我在思考如何让我的一个项目中的某个操作更高效。当前实现中的操作从对象存储中加载所有对象,遍历数组并测试对象是否缺少 属性 或者 属性 是否未定义,将此类对象的集合收集到一个第二个数组,然后删除所有这些对象。
我已经在使用 getAll,因为它比游标迭代具有明显的性能优势。
我同时调用单独的删除请求,所以除了 indexedDB api 发展到支持对缺少值的非索引非键路径道具的批量删除之外,那里没有加速。
问题是,如果 属性 不在对象存储的键路径中,而没有将每个对象完全加载到内存中,我无法检查 属性。在某些情况下,对象相当大。有时每个对象的其中一个属性非常大(本质上是一个 html 文档的字符串)。
我不能使用索引,因为对象中不存在的属性或没有值的属性不会出现在索引中。
有没有办法避免将此类对象加载到内存中?
我考虑过分区,并使用两个对象存储,一个用于可查询的道具,一个用于完整数据。但是这会导致每次读取都必须执行额外的请求。我的应用比这个偶尔的批量删除操作做更多的阅读。
我考虑过为每个对象存储一个额外的 属性,它总是有一个像 myObject.doesOtherPropertyHaveValue
这样的值,它包含 0/1,因此是可索引的,但这似乎也不太好。当然,我可以仅通过该索引进行查询并使用 getAllKeys 来解决问题。但是,现在每个 add/put 都必须保持这种功能依赖性。
如有任何建议,我们将不胜感激。
您走在正确的道路上,反规范化可能是提高性能所必需的。不幸的是,从 indexedDB 文档中无法查询您需要的方式。
如果真正的瓶颈是 I/O 或将数据编组到 JS 领域,那么也许尝试在写入之前压缩数据,并在您实际需要对数据执行某些操作时解压缩? GZIP 可以很好地压缩文本,有时最多可压缩 70%。有一些适用于 JS 的 GZIP 库可以工作:
https://github.com/nodeca/pako
但是,一如既往,基准!
如果记录的形式为 {key, prop}
,其中 prop 可能不存在,您可以在 [key, prop]
上创建索引。当 prop 存在时,这只会有索引记录。然后打开两个仅键游标:一个在存储 (C1) 上,一个在索引 (C2) 上。检查 C1.primaryKey 是否等于 C2.primaryKey[0]。如果是这样,则道具存在,同时推进两者。如果键 不 相等,则 C1 指向没有 prop 的记录;删除它并推进C1。重复。 (当你到达范围的末端时注意边缘情况。)
这有两个问题:(1) 您仍在使用游标,因此仍需支付往返费用(与 getAll()
不同),以及 (2) 如果 prop 很大(即HTML 您提到的文档)然后即使只是使用键游标,您仍然会在周围移动大量数据。
(将来我们想通过添加 more general query mechanism or custom indexing possibly combined with delete-on-index 来解决这个问题——其中任何一个都会使这更容易和更有效)
...collecting the set of such objects in a second array, and then removing all of these objects...
如果您坚持使用这种方法,请记住您可以在找到它们时发出 delete()
调用;无需收集所有对象,也无需等待删除完成;您可以以 "fire and forget" 的方式使用 IDB 进行写操作。
我在思考如何让我的一个项目中的某个操作更高效。当前实现中的操作从对象存储中加载所有对象,遍历数组并测试对象是否缺少 属性 或者 属性 是否未定义,将此类对象的集合收集到一个第二个数组,然后删除所有这些对象。
我已经在使用 getAll,因为它比游标迭代具有明显的性能优势。
我同时调用单独的删除请求,所以除了 indexedDB api 发展到支持对缺少值的非索引非键路径道具的批量删除之外,那里没有加速。
问题是,如果 属性 不在对象存储的键路径中,而没有将每个对象完全加载到内存中,我无法检查 属性。在某些情况下,对象相当大。有时每个对象的其中一个属性非常大(本质上是一个 html 文档的字符串)。
我不能使用索引,因为对象中不存在的属性或没有值的属性不会出现在索引中。
有没有办法避免将此类对象加载到内存中?
我考虑过分区,并使用两个对象存储,一个用于可查询的道具,一个用于完整数据。但是这会导致每次读取都必须执行额外的请求。我的应用比这个偶尔的批量删除操作做更多的阅读。
我考虑过为每个对象存储一个额外的 属性,它总是有一个像 myObject.doesOtherPropertyHaveValue
这样的值,它包含 0/1,因此是可索引的,但这似乎也不太好。当然,我可以仅通过该索引进行查询并使用 getAllKeys 来解决问题。但是,现在每个 add/put 都必须保持这种功能依赖性。
如有任何建议,我们将不胜感激。
您走在正确的道路上,反规范化可能是提高性能所必需的。不幸的是,从 indexedDB 文档中无法查询您需要的方式。
如果真正的瓶颈是 I/O 或将数据编组到 JS 领域,那么也许尝试在写入之前压缩数据,并在您实际需要对数据执行某些操作时解压缩? GZIP 可以很好地压缩文本,有时最多可压缩 70%。有一些适用于 JS 的 GZIP 库可以工作:
https://github.com/nodeca/pako
但是,一如既往,基准!
如果记录的形式为 {key, prop}
,其中 prop 可能不存在,您可以在 [key, prop]
上创建索引。当 prop 存在时,这只会有索引记录。然后打开两个仅键游标:一个在存储 (C1) 上,一个在索引 (C2) 上。检查 C1.primaryKey 是否等于 C2.primaryKey[0]。如果是这样,则道具存在,同时推进两者。如果键 不 相等,则 C1 指向没有 prop 的记录;删除它并推进C1。重复。 (当你到达范围的末端时注意边缘情况。)
这有两个问题:(1) 您仍在使用游标,因此仍需支付往返费用(与 getAll()
不同),以及 (2) 如果 prop 很大(即HTML 您提到的文档)然后即使只是使用键游标,您仍然会在周围移动大量数据。
(将来我们想通过添加 more general query mechanism or custom indexing possibly combined with delete-on-index 来解决这个问题——其中任何一个都会使这更容易和更有效)
...collecting the set of such objects in a second array, and then removing all of these objects...
如果您坚持使用这种方法,请记住您可以在找到它们时发出 delete()
调用;无需收集所有对象,也无需等待删除完成;您可以以 "fire and forget" 的方式使用 IDB 进行写操作。