Я использую dexie.js для взаимодействия с IndexedDB. Мне интересно, можно ли упорядочивать или сортировать по нескольким индексам одновременно (например, db.people.orderBy (index1, desc: index2, asc)... Если это возможно, каков правильный синтаксис?
Dexie.js — заказ с более чем одним индексом
Ответы (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, и они уже его поддерживают.