【问题标题】:Search Dexie table for a key in an array在 Dexie 表中搜索数组中的键
【发布时间】:2019-11-30 22:19:13
【问题描述】:

如果我在 indexedDB/Dexie 表中有以下记录:

{
  id: 1,
  name: "foo",
  children: [{id: 12, bar: "b"},
             {id: 14, bar: "c"}]
}

每个子 ID 都是唯一的。也就是说,只有 1 条记录会有一个给定 id 为 14 的孩子。

  1. 如何为孩子设置索引,以便我可以搜索包含 id 为 14 的孩子的记录?
  2. 然后我如何最有效地搜索包含具有anyOf([3, 7, 9]) 键的子项的多条记录

【问题讨论】:

    标签: indexeddb dexie


    【解决方案1】:

    IndexedDB 允许 MultiEntry 索引,但仅限于简单数组,而不是对象数组。但是您可以通过在包含所有 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 的 Edge 浏览器将支持。

    替代方法

    另一种方法是以关系方式设计表格:

    const db = new Dexie("relDB");
    db.version(1).stores({
      parents: "++id",
      children: "++id, parentId"
    });
    

    父对象:

    {
      id: 1,
      name: "foo",
    }
    

    子对象:

    {id: 12, bar: "b", parentId: 1}
    {id: 14, bar: "c", parentId: 1}
    

    然后,要根据一组子 ID [12, 14] 检索父级,请对子表使用 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]);
    

    结论

    我提出了两种可选方法,它们都可以有效地解决您的问题。第一个选项是添加一个简单的子 ID 数组和使用 MultiEntry 索引的索引,另一个选项是将子项放在单独的表中。如果您选择第二个选项,您还可以通过使用 dexie-relationships 插件来查询包含父母的孩子或包含孩子的父母。

    注意

    我将 parentId 索引到子级的原因是,在关系模式中这样做是一种很好的做法,以便能够查询所有子级以查找某个父级(此处未举例说明)。

    【讨论】:

      【解决方案2】:

      考虑将父数据冗余存储在子对象中。例如。表中的对象如下所示:

      {
        "parent" : {
          "id": 1,
          "name": "foo",
        },
        "id": 12,
        "bar": "a"
      }
      

      然后您可以在 id 上创建索引。或者,因为child id是object key,其实不需要创建索引,可以查询object store的key path。

      但是,您不能进行IN 样式查询。因为 IN 本质上是 id = 1 or id = 2 or id = 3 的简写,它是一个联合,在 indexedDB 中是无法做到的。至少效率不高。在这种情况下,您需要做的是创建 3 个查询,每个查询一个,每个查询针对相同的索引(或对象存储的键路径),然后将结果合并到一个数组中。

      【讨论】:

      • 这种方法有效,但会使用普通索引,而不是多条目索引。此外,根据其他用例,我宁愿推荐一种关系方法(儿童表和父表之间的引用),因为它会涵盖更多用例(例如首先查询父母,然后还包括这些父母的孩子)。此外,IN 样式查询在 indexedDB 中可以非常有效地完成。例如,Dexie3 中新的 bulkGet() 方法将对所有给定的键进行并行查询,这是一种快速获得所有答案的相当快的方法。 anyOf() 仍然是串行的,但可以优化。
      • @DavidFahlander 很高兴听到有关 bulkGet 的消息,但是,我认为我的观点仍然存在,bulkGet 仍在执行多个查询而不是单个查询。无论你如何旋转它,这都是次优的。
      • 你可能对效率是真的,我还没有数字,但我的共鸣是这样的:idb 调用的成本几乎是往返加上物理查找、遍历和内部数据处理leveldb 内部。但是任何 db 引擎,包括 sql 引擎都需要在引擎盖下以完全相同的方式从 IN 查询中对每个键进行一次查找(可能很幸运,并且可以在同一页面中找到所有内容......所以几乎是真的)和往返通过同时发送查询来消除成本...
      【解决方案3】:

      看起来像:

      1. 只有Indexable Types 可以用于多条目索引
      2. Edge 仍然不支持多条目键的索引数据库标准!!!坦率地说很荒谬。
      3. 允许原始问题has been suggested 中描述的行为

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-09-01
        • 2023-04-09
        • 2011-04-27
        • 2019-04-16
        • 2020-01-15
        • 1970-01-01
        • 2019-10-29
        相关资源
        最近更新 更多