Dexie.js — заказ с более чем одним индексом

Я использую dexie.js для взаимодействия с IndexedDB. Мне интересно, можно ли упорядочивать или сортировать по нескольким индексам одновременно (например, db.people.orderBy (index1, desc: index2, asc)... Если это возможно, каков правильный синтаксис?


person Rob Welan    schedule 28.02.2016    source источник


Ответы (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()

Во-первых, выберите наиболее вероятный индекс для начала поиска. В этом случае «имя» будет идеальным индексом, который не будет соответствовать такому количеству элементов, в то время как возраст или размер обуви, вероятно, будут соответствовать большему количеству друзей.

Схема:

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);
        });
}

Используйте здесь функции стрелок, чтобы сделать текст более читабельным. Кроме того, вы ориентируетесь на хром или Firefox, и они уже его поддерживают.

person David Fahlander    schedule 11.04.2016
comment
Куда приходит заказ? - person Benjamin H; 21.12.2018
comment
@BenjaminH, у тебя есть решение? - person user4156958; 07.04.2021
comment
Извините, бросил это некоторое время назад. - person Benjamin H; 09.04.2021