indexeddb多索引排序

dy2hfwbg  于 2021-06-21  发布在  Mysql
关注(0)|答案(1)|浏览(669)

我有一个文件对象存储索引 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模型截图供参考。
24536475 , `` , created , jhgf 以及 lastmodified 文件名属于名为 123 . Screen Shot..* 文件名属于另一个名为 234 .
我需要的文件是按名称排序,只有给定的图书馆id。任何帮助将不胜感激。

r7knjye2

r7knjye21#

如果您的索引基于属性数组,并且希望使用 IDBKeyRange.only ,然后将参数 IDBKeyRange.only 也应该是数组。现在比较的是基本字符串值和属性数组值,当然没有匹配的。换句话说,不能仅使用两部分数组的一部分来查询它。
此外,idbkeyrange.only的参数不是属性名,而是一个值。您想在索引的键路径值集中指定一个要匹配的值。例如,如果索引完全基于attributes.name,则需要在该索引中指定一个特定值,例如“”。
因此,考虑到以上两点,并且假设您的索引不是一个单一的值,而是一个由两个属性组成的数组,您需要将参数修改为idbkeyrange.only以查找数组。像这样的 IDBKeyRange.only(['', '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 index属性相混淆,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']);

看看结果。
最后的一些注意事项:
tilde可能是使用错误的东西,对不起,我不想麻烦记住,您也可以尝试任何有效的sentinel值,其中sentinel是指您知道的任何值总是在所有其他有效值之后
正如我在另一个答案中指出的,如果数据中缺少任何一个道具,那么实际对象将不匹配
对于cmp,-1表示左小于右,0表示左等于右,1表示左大于右

相关问题