具有多个索引的Indexeddb排序

时间:2018-07-11 11:55:55

标签: mysql sorting filtering indexeddb querying

通过索引name and library_id来获得文件对象存储,如下所示,

let objectStore = db.createObjectStore('file', { keyPath: 'id' });
    tempStore.createIndex('nameLibId', ['attributes.name', 'attributes.library_id'], { unique: false });

对象库包含多个库ID的文件。我想将名称排序应用于特定库ID的文件。我尝试使用以下格式编制索引,但它返回的数据为空。

    let self = this, 
        db = get(self, 'db'),
        transaction = db.transaction(["file"], "readonly"),
        objectStore = transaction.objectStore("file"),
        index = objectStore.index('nameLibId'),
        keyRange = IDBKeyRange.only('library_id')),
        req = index.getAll(keyRange);
        req.onsuccess = ((e)=>{
          console.log(e.target.result); // returns empty array
        });

随附了db模型的屏幕快照以供参考。

enter image description here

  1. 24536475abccreatedjhgflastmodified文件名属于名为123的库ID。

  2. Screen Shot..*文件名属于另一个名为234的库ID。

我只需要按给定库ID按名称排序的文件。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:1)

如果索引基于属性数组,并且您想使用IDBKeyRange.only进行匹配,则IDBKeyRange.only的参数也应该是数组。现在,您正在将一个基本字符串值与一个属性数组值进行比较,其中当然没有任何匹配项。换句话说,您不能仅使用其中一部分来查询由两部分组成的数组。

此外,IDBKeyRange.only的参数不是属性名称,而是一个值。您想要指定一个与索引的键路径值集中匹配的值。例如,如果您的索引仅基于attributes.name,则您需要在该索引中指定一个特定的值,例如“ abc”。

因此,考虑到以上两点,并且考虑到您的索引不是单个值而是由两个属性组成的数组,因此您需要将参数修改为IDBKeyRange.only,以查找数组。像IDBKeyRange.only(['abc', 'yoktc....']);之类的东西。

现在,由于您在代码中执行的操作实际上并未完成所需的操作,这使情况更加复杂。暂时忽略排序问题,在匹配此索引的行时,您只想使用id条件,而不是名称。因此,您可能很想尝试IDBKeyRange.only([undefined, 'asdf'])。不幸的是,这根本不起作用,因为您无法指定undefined(您将收到javascript错误)。

因此,即使您只想将标准应用于其中一个值,也必须始终按两个值查询。这里的窍门是,您切换到使用不同于其他方法的方法。您使用IDBKeyRange.bound(),并且还可以通过技巧来指定诸如“最小的可能的数字小于我的数字,而我的数字小于最大的数字”之类的条件。一个永远都是真的条件。您将“最小可能值”用作下边界,而将“最大可能值”用作上边界。

这里是您的例子。我认为name的最小可能值是空字符串。 name的最大可能值可能是任何非字母数字字符,因此让我们使用代字号“〜”。因此,现在我们将重写range参数。代替使用IDBKeyRange.only,我们使用IDBKeyRange.bound。看起来如下(大致):

var libId = ???;
var smallestNameValue = '';
var largestNameValue = '~';
var lowerBound = [smallestNameValue, libId];
var upperBOund = [largestNameValue, libId];
var range = IDBKeyRange.bound(lowerBound, upperBound);

现在,第二部分关于排序,以及使用具有多个部分的索引的主要警告(不要与multiPart索引属性ugh混淆)。而且我本人一直都在退缩,所以我什至在这里可能是错的,并且上面的方法行得通。上面的问题是,由于短路数组排序算法在indexedDB的比较函数中是如何工作的,因此第一个条件被满足,第二个条件被忽略了。您的查询将匹配所有内容,因为每个索引行均符合条件。因此,此方法的诀窍是始终首先查询重要条件,基本上要注意您指定条件的顺序。因此,这意味着您需要在创建索引时切换指定属性的顺序,以便可以先按libId然后按名称查询。

您想要执行createIndex('nameLibId',['attributes.name','attributes.library_id']);而不是createIndex('nameLibId',['attributes.library_id', 'attributes.name']);。这也意味着您需要交换下限和上限查询,例如var lowerBound = [libId, smallestNameValue];(并且不要忘记切换鞋帮)。

正如我在回答中使用复合索引所提到的那样,您始终可以使用indexedDB.cmp进行实验。现在,在此网页上打开控制台。在控制台中,输入以下内容:

indexedDB.cmp(['', '5'], ['~', '5']);

看看结果。

一些最后的笔记:

  • 使用波浪号可能是错误的事情,对不起,但我不想烦恼,您也可以尝试使用任何有效的前哨值,其中前哨指的是您知道的任何值将始终出现在所有其他有效值之后< / li>
  • 正如我在其他答案中指出的那样,如果数据中缺少任何一个道具,则实际对象将不匹配
  • 对于cmp,-1表示左小于右,0表示左等于右,而1表示左大于右