1

我正在使用 dexie.js 与 IndexedDB 交互。我想知道是否可以一次使用多个索引进行排序或排序(例如 db.people.orderBy( index1, desc : index2, asc )...如果可能,正确的语法是什么?

4

1 回答 1

1

要么使用复合索引,要么使用 Collection.and()。

如果你只能忍受 Chrome、Firefox 或 Opera,你可以使用复合索引。如果它必须在 Safari、IndexedDBShim、Edge 或 IE 上运行,那么您现在不能使用复合索引。虽然有一个shim可以为 IE/Edge 启用它,但它仍处于测试阶段,所以我建议在这些情况下使用 Collection.and()。

假设您有一个表单,用户可以在其中填写朋友的各种属性:

<form>
  <input name="name"/>
  <input name="age"/>
  <input name="shoeSize" />
</form>

使用 Collection.and()

首先,选择最有可能开始搜索的索引。在这种情况下,“name”将是一个完美的索引,它不会匹配这么多的项目,而 age 或 shoeSize 可能会匹配更多的朋友。

架构:

db.version(X).stores({
    friends: "id, name, age, shoeSize"
});

询问:

function prepareQuery () {
    // Pick a good index. The picked index will filter out with IndexedDB's built-in keyrange
    var query;
    if (form.name.value) {
        query = db.friends.where('name').equals(form.name.value);
    } else if (form.age.value) {
        query = db.friends.where('age').equals(parseInt(form.age.value));
    } else if (form.shoeSize.value) {
        query = db.friends.where('shoeSize').equals(parseInt(form.shoeSize.value));
    } else {
        query = db.friends.toCollection();
    }

    // Then manually filter the result. May filter a field that the DB has already filtered out,
    // but the time that takes is negligible.
    return query.and (function (friend) {
        return (
            (!form.name.value || friend.name === form.name.value) &&
            (!form.age.value || friend.age == form.age.value) &&
            (!form.shoeSize.value || friend.shoeSize == form.shoeSize.value));
    });
}

// Run the query:
form.onsubmit = function () {
    prepareQuery() // Returns a Collection
        .limit(25) // Optionally add a limit onto the Collection
        .toArray(function (result) { // Execute query
            alert (JSON.stringify(result, null, 4));
        })
        .catch (function (e) {
            alert ("Oops: " + e);
        });
}

使用复合索引

如上所述,复合索引代码仅适用于基于 mozilla 和 chromium 的浏览器。

db.version(x).stores({
    friends: "id, name, age, shoeSize," +
        "[name+age+shoeSize]," +
        "[name+shoeSize]," +
        "[name+age]," +
        "[age+shoeSize]"
});

使用复合索引时的 prepareQuery() 函数:

function prepareQuery() {
    var indexes = []; // Array of Array[index, key]
    if (form.name.value)
        indexes.push(["name", form.name.value]);
    if (form.age.value)
        indexes.push(["age", parseInt(form.age.value)]);
    if (form.shoeSize.value)
        indexes.push(["shoeSize", parseInt(form.shoeSize.value)]);

    var index = indexes.map(x => x[0]).join('+'),
        keys = indexes.map(x => x[1]);

    if (indexes.length === 0) {
        // No field filled in. Return unfiltered Collection
        return db.friends.toCollection();
    } else if (indexes.length === 1) {
        // Single field filled in. Use simple index:
        return db.friends.where(index).equals(keys[0]);
    } else {
        // Multiple fields filled in. Use compound index:
        return db.friends.where("[" + index + "]").equals(keys);
    }
}

// Run the query:
form.onsubmit = function () {
    prepareQuery() // Returns a Collection
        .limit(25) // Optionally add a limit onto the Collection
        .toArray(function (result) { // Execute query
            alert (JSON.stringify(result, null, 4));
        })
        .catch (function (e) {
            alert ("Oops: " + e);
        });
}

在此处使用箭头函数使其更具可读性。此外,您的目标是铬或火狐,他们已经支持它。

于 2016-04-11T10:23:26.843 回答