IndexedDB - 布尔型索引

20

能否在布尔类型字段上创建索引?

假设我想要存储的记录模式如下:

{
  id:1,
  name:"Kris",
  _dirty:true
}

我创建了一个普通的非唯一索引(onupgradeneeded):

...
store.createIndex("dirty","_dirty",{ unique: false })
...

索引已创建,但是它是空的!- 在IndexedDB浏览器中,没有记录包含布尔值 - 只有字符串数字日期,甚至数组

我正在使用Chrome 25 canary。

我想找到所有具有设置为true的_dirty属性的记录 - 我必须将_dirty修改为字符串或整数吗?

5个回答

11

标记为已勾选的答案并不完全正确。

您无法在包含布尔类型值的属性上创建索引。其他答案中的这部分是正确的。如果您有一个对象,例如 var obj = {isActive: true}; 尝试在 obj.isActive 上创建索引将不起作用,并且浏览器会报告错误消息。

但是,您可以轻松模拟所需的结果。indexedDB 不会将不存在于对象中的属性插入到索引中。因此,您可以定义一个属性来表示 true,并不定义该属性来表示 false。当该属性存在时,该对象将出现在索引中。当该属性不存在时,该对象将不会出现在索引中。

示例

例如,假设您有一个名为 “obj” 的对象存储区。假设您想在这些对象的 isActive 属性上创建类似布尔型的索引。

首先,在 onupgradeneeded 回调函数中创建 isActive 属性的索引。使用 store.createIndex('isActive','isActive');

要表示对象的“true”,只需使用 obj.isActive = 1; 然后将对象添加或放入对象存储区。当您想要查询所有设置了 isActive 的对象时,只需使用 db.transaction('store').index('isActive').openCursor();

要表示 false,只需使用 delete obj.isActive; 然后将对象添加或放入对象存储区。

当您查询所有设置了 isActive 的对象时,这些缺少 isActive 属性的对象(因为它已被删除或从未设置)在使用游标迭代时不会出现。

就这样,一个布尔型索引。

性能注意事项

在像这里使用的示例中打开索引的光标将提供良好的性能。对于小数据,性能差异不明显,但在存储大量对象时非常明显。没有必要采用第三方库来完成“布尔索引”。这是一个平凡而简单的功能,您可以自己做。应尽可能使用本地功能。


这是一个很棒的贡献。你做过任何跨浏览器测试吗? - Robert
这里的建议只会获取到索引的一半,你可以轻松查找 isActive 值为真的对象,但无法查找 isActive 值为的对象。一个真正的索引布尔字段可以让你查找值为真或值为假的对象。 - Ben
如果你想通过false进行查询,那么请使用1和0代替true和false,并在0上开启一个范围查询,例如openCursor(0)openCursor(IDBKeyRange.only(0)) - Josh
@Josh 对的。所以我猜问题不在于被接受的答案完全不正确,而是它提出了一种与你所提出的布尔索引模拟不同(更完整)的方法(使用两个可索引类型的任意值来表示真/假,而不是可索引属性的存在/缺失)。该死,我原本希望自己漏掉了什么;这种方法似乎比在每个地方都记得使用虚假布尔值要好一些,但我确实需要能够查询假/缺失情况以及真/存在情况。 - Ben
@Josh 虽然我和你一样,不同意布尔索引没有用的说法。但是标准的撰写者为什么会把它们忽略掉呢?唉,算了吧。 - Ben

9

是的,布尔值不是有效的键

当然,如果必要的话,你可以将其解决为1和0。

但这是有充分理由的。索引布尔值没有信息价值。在您上述情况中,您可以进行表扫描并即时过滤,而不是索引查询。


3
答案正确,但我不同意其推理。在处理大量记录时,索引布尔值会提供信息。即时过滤是完全浪费处理能力的。而将键的值存储为0而不是根本不存储键是浪费空间的行为。 - Josh
索引只有在能够以O(log n)的查找时间检索请求键时才有用。对于布尔索引,无论是否进行了索引,查找时间都是相同的。 - Kyaw Tun
我认为我必须再次尊重地不同意。在执行代码时,store.openCursor(...).onsuccess = function() { if(this.result.value.someBoolean) { ... }} 和 store.index(...).openCursor(...).onsuccess = function() {} 之间存在显着的性能差异。 - Josh
恕我再次反驳。您是正确的,使用 index.openCursor 查询速度确实比 store.openCursor 更快,但仅对于布尔索引值而言,速度提升只有50%。在渐进情况下,这并不显著。 - Kyaw Tun
23
这个推理需要假设50%的对象是真实的,而另外50%是虚假的。但在现实世界中,你可能会有10万个对象都是虚假的,只有极少数是真实的。在这种情况下,索引一个布尔值确实是有意义的。 - David Fahlander

1

我使用了01代替布尔类型。


1
另一种选择是将数据拆分为两个独立的对象存储,分别为commands_synced_to_servercommands_not_synced_to_server
然后,读取所有commands_not_synced_to_server是最快的,因为不需要通过索引查找数据,而且只需读取所需的项目。
缺点包括:
  • 增加了复杂性。
  • 如果更新布尔字段,您需要从true_values对象存储中删除该项,并将其插入false_values对象存储中。
  • 如果查询时不知道布尔值,则需要查询两个对象存储。由于查询是异步运行的,我认为与单个存储相比,性能差异不大。您还可以将所有数据复制到第三个对象存储中以优化此情况。

0

布尔属性描述了独占状态(激活/停用),'开/关','启用/禁用','是/否'。您可以在JS数据模型中使用这些值对代替布尔值以提高可读性。此外,此策略允许添加其他状态(例如“未设置”,如果对象中的某些内容未配置等)...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接