IndexedDB“和”和“或”查询
IndexedDB “and” and “or” queries
我将以下内容存储在 IndexedDB 中:
[
{
name: 'pizza',
ingredients: [ 'flour', 'water', 'yeast', 'salt', 'oil' ]
}, {
name: 'pasta',
ingredients: [ 'semolina', 'salt', 'water' ]
}, …
]
我在 ingredients
上有一个 multiEntry
索引:
store.createIndex('ingredientIdx', 'ingredients', { multiEntry: true });
现在,我想得到:
含有任何给定成分的膳食,例如flour
或water
含有所有给定成分的膳食,例如semolina
、salt
、和 water
我的天真方法目前对每个给定的成分执行多个查询,然后对结果进行过滤和重复数据删除。但这感觉一点也不像“数据库”。
IndexedDB 是否支持某种“或”或“和”查询?这样做显然 不起作用 :
const tx = db.transaction('meals');
const ingredientIdx = tx.objectStore('meals').index('ingredientsIdx');
const request = ingredientIdx.getAll([ 'flour' , 'water' ]);
// …
您已正确设置商店并正确使用索引并且正确地一次查询一个。您设置所有内容的方式没有任何问题。然而,不幸的是,indexedDB 并不能轻松地以您想要的方式有效地查询该数据,例如通过使用单个 cursor/getAll.
匹配多个对象
第一个问题是关于OR的使用。您不能在单个请求中执行此操作。您将需要执行多个请求。请注意,您至少可以同时执行这些请求。遍历操作数并从多条目索引中获取每个操作数,将每个结果附加到每个请求共享的单个数组中,同时考虑重复项。您需要以一种方式执行此操作,以便每个后续请求都不会在开始之前等待先前的请求完成。
第二个问题是关于AND的使用。您只能对一系列值进行 AND 式查询,例如就像这个下限和上限之间的所有数字一样。因此,您需要像现在一样一次查询一个。
关于 AND,您可以考虑聪明一点,以不同的方式构建数据。例如,为每种成分创建布尔值(使用 0 和 1)属性。例如。如果披萨有面粉,那么披萨对象有一个名为 ingredient_flour
的 属性,值为 1,如果披萨没有面粉,它要么没有 属性,要么有 属性 ingrediant_flour
的值为 0。然后您可以在不同的成分组合上创建各种索引。例如。您可以在面粉和水上创建一个索引,然后查询该索引以获取 IDBKeyRange.only([1,1])
.
并发 OR 示例(类似这样):
function any(db, values) {
return new Promise((resolve, reject) => {
const objects = [];
const transaction = db.transaction('meals');
transaction.oncomplete = function(event) {
resolve(objects);
};
transaction.onerror = function(event) {
reject(event.target.error);
};
const store = transaction.objectStore('meals');
const index = store.index('ingredients');
function onsuccess(event) {
const cursor = event.target.result;
if (cursor) {
const value = cursor.value;
let exists = false;
for (const object of objects) {
if (object.name === value.name) {
exists = true;
break;
}
}
if (!exists) {
objects.push(value);
}
cursor.continue();
}
}
for (const value of values) {
// IDBKeyRange.only is implied in this next line
const request = index.get(value);
request.onsuccess = onsuccess;
}
});
}
我将以下内容存储在 IndexedDB 中:
[
{
name: 'pizza',
ingredients: [ 'flour', 'water', 'yeast', 'salt', 'oil' ]
}, {
name: 'pasta',
ingredients: [ 'semolina', 'salt', 'water' ]
}, …
]
我在 ingredients
上有一个 multiEntry
索引:
store.createIndex('ingredientIdx', 'ingredients', { multiEntry: true });
现在,我想得到:
含有任何给定成分的膳食,例如
flour
或water
含有所有给定成分的膳食,例如
semolina
、salt
、和water
我的天真方法目前对每个给定的成分执行多个查询,然后对结果进行过滤和重复数据删除。但这感觉一点也不像“数据库”。
IndexedDB 是否支持某种“或”或“和”查询?这样做显然 不起作用 :
const tx = db.transaction('meals');
const ingredientIdx = tx.objectStore('meals').index('ingredientsIdx');
const request = ingredientIdx.getAll([ 'flour' , 'water' ]);
// …
您已正确设置商店并正确使用索引并且正确地一次查询一个。您设置所有内容的方式没有任何问题。然而,不幸的是,indexedDB 并不能轻松地以您想要的方式有效地查询该数据,例如通过使用单个 cursor/getAll.
匹配多个对象第一个问题是关于OR的使用。您不能在单个请求中执行此操作。您将需要执行多个请求。请注意,您至少可以同时执行这些请求。遍历操作数并从多条目索引中获取每个操作数,将每个结果附加到每个请求共享的单个数组中,同时考虑重复项。您需要以一种方式执行此操作,以便每个后续请求都不会在开始之前等待先前的请求完成。
第二个问题是关于AND的使用。您只能对一系列值进行 AND 式查询,例如就像这个下限和上限之间的所有数字一样。因此,您需要像现在一样一次查询一个。
关于 AND,您可以考虑聪明一点,以不同的方式构建数据。例如,为每种成分创建布尔值(使用 0 和 1)属性。例如。如果披萨有面粉,那么披萨对象有一个名为 ingredient_flour
的 属性,值为 1,如果披萨没有面粉,它要么没有 属性,要么有 属性 ingrediant_flour
的值为 0。然后您可以在不同的成分组合上创建各种索引。例如。您可以在面粉和水上创建一个索引,然后查询该索引以获取 IDBKeyRange.only([1,1])
.
并发 OR 示例(类似这样):
function any(db, values) {
return new Promise((resolve, reject) => {
const objects = [];
const transaction = db.transaction('meals');
transaction.oncomplete = function(event) {
resolve(objects);
};
transaction.onerror = function(event) {
reject(event.target.error);
};
const store = transaction.objectStore('meals');
const index = store.index('ingredients');
function onsuccess(event) {
const cursor = event.target.result;
if (cursor) {
const value = cursor.value;
let exists = false;
for (const object of objects) {
if (object.name === value.name) {
exists = true;
break;
}
}
if (!exists) {
objects.push(value);
}
cursor.continue();
}
}
for (const value of values) {
// IDBKeyRange.only is implied in this next line
const request = index.get(value);
request.onsuccess = onsuccess;
}
});
}