IDBKeyRange与复合索引的奇怪行为

时间:2014-10-04 19:55:03

标签: javascript indexeddb

Here's my test case on JS Bin.

想象一下,你有一个IndexedDB对象存储。您的对象非常简单,有两个属性“a”和“b”。两个属性都包含整数。并且因为您希望能够在对象存储中查询“a”和“b”的特定值,所以可以创建复合索引。以下是一些遵循此描述的代码:

var db;

request = indexedDB.open("test", 1);
request.onerror = function (event) { console.log(event); };

request.onupgradeneeded = function (event) {
  var db = event.target.result;
  db.onerror = function (event) { console.log(event); };

  var store = db.createObjectStore("store", {keyPath: "id", autoIncrement: true});
  store.createIndex("a, b", ["a", "b"], {unique: true});

  store.add({a: 0, b: 0});
  store.add({a: 1, b: 0});
  store.add({a: 1, b: 1});
};

request.onsuccess = function (event) {
  db = request.result;
  db.onerror = function (event) { console.log(event); };
};

如果要从数据库中检索特定对象,则可以正常工作。所以如果你运行这个:

db.transaction("store").objectStore("store").index("a, b").get([1, 0]).onsuccess = function (event) { console.log(event.target.result); };

输出是:

Object {a: 1, b: 0, psid: 2} 

奇妙。大。所以现在你要检索一系列值。说,你想把“b”固定为0,同时让“a”为0或1.现在奇怪的东西开始发生了。试试这段代码:

console.log("[a, b] bound from [0, 0] to [1, 0]");
db.transaction("store").objectStore("store").index("a, b").openCursor(IDBKeyRange.bound([0, 0], [1, 0])).onsuccess = function (event) {
  var cursor = event.target.result;
  if (cursor) {
    console.log(cursor.value);
    cursor.continue();
  } else {
    console.log("[a, b] bound from [0, 0] to [2, 0]");
    db.transaction("store").objectStore("store").index("a, b").openCursor(IDBKeyRange.bound([0, 0], [2, 0])).onsuccess = function (event) {
      var cursor = event.target.result;
      if (cursor) {
        console.log(cursor.value);
        cursor.continue();
      }
    };
  }
};

它产生这个输出:

[a, b] bound from [0, 0] to [1, 0]
Object {a: 0, b: 0, id: 1}
Object {a: 1, b: 0, id: 2}
[a, b] bound from [0, 0] to [2, 0]
Object {a: 0, b: 0, id: 1}
Object {a: 1, b: 0, id: 2}
Object {a: 1, b: 1, id: 3}

[0,0]和[1,0]之间的界限似乎工作正常。但是[0,0]和[2,0]之间的界限不是!结果它也返回[0,1]。为什么[1,0]作为上限但[2,0]不起作用?我觉得我必须犯下一个非常愚蠢的错误,或者从根本上误解某些事情。

万一你错过了,here is the link to this on JS Bin again

Josh的编辑:我最初只用bound(x,y)尝试了它,与bound(x,y,false,false)相同。可以将其更改为bound(x,y,true,true) here。输出

[a, b] bound from [0, 0] to [1, 0]
[a, b] bound from [0, 0] to [2, 0]
Object {a: 1, b: 0, id: 2}
Object {a: 1, b: 1, id: 3}

我对这些东西的理解仍然没有很好的直观理解。

2 个答案:

答案 0 :(得分:1)

我试图在the other answer中解释这一点,但基本上是因为indexedDB规范中定义的短路数组排序。您正在使用范围查询,并且所有匹配都在第一个范围内。如果满足第一个范围标准,则其余范围正在做什么并不重要。

没有解决方案。您可以创建单独的索引(但遇到爆炸式索引问题)。您可以改为为每个对象创建预先计算的字段。换句话说,不要使用复合索引,在每次在indexedDB中添加/更新对象时更新对象的特殊派生隐藏字段时使用单个索引。

答案 1 :(得分:1)

您的索引不适用于查询b的修正值。使用复合索引时,认为复合索引有两部分prefix and postfix。前缀密钥路径是您要过滤的路径。 postfix是您要订购的。

在您的情况下,您希望按b进行过滤,然后按a排序,因此索引应为['b', 'a']。由于前缀和后缀keyPath可以有多个字段,因此可以使用IndexedDB进行非常复杂的查询。

相关问题