IndexedDB - 如何创建和使用简单和复杂的 IDBIndex keyPaths?
IndexedDB - How to create and use simple and complex IDBIndex keyPaths?
我想创建和使用两个 IndexedDB 索引,一个具有简单的 keyPath,另一个具有复杂的 keyPath。虽然在我试过的每个浏览器中都创建成功,但索引似乎在大多数情况下都没有正确填写。
我正在使用的过程(问题末尾的独立测试用例)是:
使用 { keyPath: 'id', autoIncrement: true }
.
创建具有单个存储的索引数据库
创建两个索引:第一个索引是用keyPath: 'id'
和{ unique: false, multiEntry: false }
创建的。第二个索引是用 keyPath: ['id', 'name']
和 { unique: false, multiEntry: false }
.
创建的
向商店添加一些 (19) 个对象,所有对象都具有 name
属性。
对两个索引调用 IDBIndex.count
。
预期 IDBIndex.count
的两次调用都会 return 商店中存在的对象总数 (19)。根据浏览器的不同,这可能会也可能不会发生:
Safari 10.0.3 简单:19,复杂:19
Chrome 57.0.2987.98 简单:19,复杂:0
Opera 43.0.2442.1144 简单:19,复杂:0
IE 11.953.14393.0 简单:0,复杂:0
边 38.14393.0.0 简单:0,复杂:0
Firefox 54.0a2 简单:0,复杂:0
如果我将索引的创建从 { unique: false, multiEntry: false }
更改为仅 { unique: false }
,则每个浏览器的行为都保持不变。
如果我将复杂索引的创建从 ['id', 'name']
更改为 (according to the spec) 等价物 id.name
,Safari 会将行为更改为 simple: 19, complex : 0¹,其他不变
如果我将复杂索引的创建从 'id'
索引更改为 ['id']
,Safari 仍然 returns 简单:19,复杂:0,每隔一个浏览器 returns 简单:0,复杂:0.
我做错了什么?如何创建多属性索引?
(我目前正在使用以下独立示例进行测试,由于使用了 indexedDB,因此无法在 Whosebug 上运行)
var deleteRequest = indexedDB.deleteDatabase('test-db');
deleteRequest.onerror = deleteRequest.onblocked = deleteRequest.onsuccess = function () {
console.log('Database deleted', arguments);
var openRequest = indexedDB.open('test-db');
openRequest.onerror = function (errorEvent) { console.log('open error', errorEvent); };
openRequest.onblocked = function (blockedEvent) { console.log('open blocked', blockedEvent); };
openRequest.onupgradeneeded = function (upgradeEvent) {
console.log('Database opened');
var database = upgradeEvent.target.result;
var store = database.createObjectStore('sochrastic', { keyPath: 'id', autoIncrement: true });
store.createIndex('index_name', ['id', 'name'], { unique: false, multiEntry: false });
store.createIndex('index_id', 'id', { unique: false, multiEntry: false });
};
openRequest.onsuccess = function (successEvent) {
console.log('Indices created');
successEvent.target.result.close();
var openRequest = indexedDB.open('test-db');
openRequest.onerror = function (errorEvent) { console.log('open error', errorEvent); };
openRequest.onblocked = function (blockedEvent) { console.log('open blocked', blockedEvent); };
openRequest.onsuccess = function (upgradeEvent) {
console.log('Database opened');
var database = upgradeEvent.target.result;
var transaction = database.transaction('sochrastic', 'readwrite');
var store = transaction.objectStore('sochrastic');
store.add({ name: 'druk', badjorance: 'animal' });
store.add({ name: 'druk', badjorance: 'beast' });
store.add({ name: 'druk', badjorance: 'canal' });
store.add({ name: 'myke', badjorance: 'dice' });
store.add({ name: 'myke', badjorance: 'evergreen' });
store.add({ name: 'myke', badjorance: 'fake' });
store.add({ name: 'myke', badjorance: 'game' });
store.add({ name: 'grey', badjorance: 'honor' });
store.add({ name: 'grey', badjorance: 'incognito' });
store.add({ name: 'grey', badjorance: 'joke' });
store.add({ name: 'grey', badjorance: 'key' });
store.add({ name: 'grey', badjorance: 'lemon' });
store.add({ name: 'brady', badjorance: 'mast' });
store.add({ name: 'brady', badjorance: 'nothing' });
store.add({ name: 'brady', badjorance: 'opera' });
store.add({ name: 'brady', badjorance: 'pear' });
store.add({ name: 'brady', badjorance: 'quote' });
store.add({ name: 'brady', badjorance: 'rodent' });
store.add({ name: 'brady', badjorance: 'sunk' });
database.close();
var openRequest = indexedDB.open('test-db');
openRequest.onerror = function (errorEvent) { console.log('open error', errorEvent); };
openRequest.onblocked = function (blockedEvent) { console.log('open blocked', blockedEvent); };
openRequest.onsuccess = function (successEvent) {
console.log('Store filled');
var database = successEvent.target.result;
var transaction = database.transaction('sochrastic', 'readonly');
var store = transaction.objectStore('sochrastic');
var indexName = store.index('index_name');
var nameCountRequest = indexName.count();
nameCountRequest.onerror = function (errorEvent) { document.querySelector('#name-id-count').textContent = 'error'; console.log(errorEvent); };
nameCountRequest.onblocked = function (blockedEvent) { document.querySelector('#name-id-count').textContent = 'blocked'; console.log(blockedEvent); };
nameCountRequest.onsuccess = function (successEvent) { document.querySelector('#name-id-count').textContent = successEvent.target.result; console.log('name-id', successEvent.target.result); };
var indexId = store.index('index_id');
var idCountRequest = indexId.count();
idCountRequest.onerror = function (errorEvent) { document.querySelector('#id-count').textContent = 'error'; console.log(errorEvent); };
idCountRequest.onblocked = function (blockedEvent) { document.querySelector('#id-count').textContent = 'blocked'; console.log(blockedEvent); };
idCountRequest.onsuccess = function (successEvent) { document.querySelector('#id-count').textContent = successEvent.target.result; console.log('id', successEvent.target.result); };
}
}
}
}
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>IndexedDB Indices</title>
</head>
<body>
<p>['id', 'name'] index result: <span id="name-id-count"></span></p>
<p>['id'] index result: <span id="id-count"></span></p>
</body>
</html>
IE 和 Edge 根本不支持复杂索引https://developer.microsoft.com/en-us/microsoft-edge/platform/status/indexeddbarraysandmultientrysupport/?q=indexeddb,但您可以在其他浏览器中使用它们。
If I change the creation of the complex index from ['id', 'name'] to the (according to the spec) equivalent id.name, Safari changes behaviour to simple: 19, complex: 0, the others remain the same.
它们并不等同。 id.name
在单个值上创建索引,如 {id: {name: 'value'}}
,['id', 'name']
在两个字段上创建复合索引,如 {id: 1, name: 'value'}
.
您的索引失败是因为您依赖于自动生成的主键 id
。如果您将 id
更改为 badjorance
,那么您的计数符合您的预期,至少在 Firefox 和 Chrome 中是这样。 (顺便说一句,即使在您的原始示例中,我也没有看到任何区别,两种浏览器都显示为 0)。
我猜有些浏览器会在将主键添加到对象之前评估 keyPath,而其他浏览器会在之后评估。至于哪种行为是正确的……我想阅读规范已经很晚了,但是除非规范不明确,否则您可能想报告浏览器中的错误。如果我是赌徒,我猜 Safari 是错误的。
我想创建和使用两个 IndexedDB 索引,一个具有简单的 keyPath,另一个具有复杂的 keyPath。虽然在我试过的每个浏览器中都创建成功,但索引似乎在大多数情况下都没有正确填写。
我正在使用的过程(问题末尾的独立测试用例)是:
使用
{ keyPath: 'id', autoIncrement: true }
. 创建具有单个存储的索引数据库
创建两个索引:第一个索引是用
keyPath: 'id'
和{ unique: false, multiEntry: false }
创建的。第二个索引是用keyPath: ['id', 'name']
和{ unique: false, multiEntry: false }
. 创建的
向商店添加一些 (19) 个对象,所有对象都具有
name
属性。对两个索引调用
IDBIndex.count
。
预期 IDBIndex.count
的两次调用都会 return 商店中存在的对象总数 (19)。根据浏览器的不同,这可能会也可能不会发生:
Safari 10.0.3 简单:19,复杂:19
Chrome 57.0.2987.98 简单:19,复杂:0
Opera 43.0.2442.1144 简单:19,复杂:0
IE 11.953.14393.0 简单:0,复杂:0
边 38.14393.0.0 简单:0,复杂:0
Firefox 54.0a2 简单:0,复杂:0
如果我将索引的创建从 { unique: false, multiEntry: false }
更改为仅 { unique: false }
,则每个浏览器的行为都保持不变。
如果我将复杂索引的创建从 ['id', 'name']
更改为 (according to the spec) 等价物 id.name
,Safari 会将行为更改为 simple: 19, complex : 0¹,其他不变
如果我将复杂索引的创建从 'id'
索引更改为 ['id']
,Safari 仍然 returns 简单:19,复杂:0,每隔一个浏览器 returns 简单:0,复杂:0.
我做错了什么?如何创建多属性索引?
(我目前正在使用以下独立示例进行测试,由于使用了 indexedDB,因此无法在 Whosebug 上运行)
var deleteRequest = indexedDB.deleteDatabase('test-db');
deleteRequest.onerror = deleteRequest.onblocked = deleteRequest.onsuccess = function () {
console.log('Database deleted', arguments);
var openRequest = indexedDB.open('test-db');
openRequest.onerror = function (errorEvent) { console.log('open error', errorEvent); };
openRequest.onblocked = function (blockedEvent) { console.log('open blocked', blockedEvent); };
openRequest.onupgradeneeded = function (upgradeEvent) {
console.log('Database opened');
var database = upgradeEvent.target.result;
var store = database.createObjectStore('sochrastic', { keyPath: 'id', autoIncrement: true });
store.createIndex('index_name', ['id', 'name'], { unique: false, multiEntry: false });
store.createIndex('index_id', 'id', { unique: false, multiEntry: false });
};
openRequest.onsuccess = function (successEvent) {
console.log('Indices created');
successEvent.target.result.close();
var openRequest = indexedDB.open('test-db');
openRequest.onerror = function (errorEvent) { console.log('open error', errorEvent); };
openRequest.onblocked = function (blockedEvent) { console.log('open blocked', blockedEvent); };
openRequest.onsuccess = function (upgradeEvent) {
console.log('Database opened');
var database = upgradeEvent.target.result;
var transaction = database.transaction('sochrastic', 'readwrite');
var store = transaction.objectStore('sochrastic');
store.add({ name: 'druk', badjorance: 'animal' });
store.add({ name: 'druk', badjorance: 'beast' });
store.add({ name: 'druk', badjorance: 'canal' });
store.add({ name: 'myke', badjorance: 'dice' });
store.add({ name: 'myke', badjorance: 'evergreen' });
store.add({ name: 'myke', badjorance: 'fake' });
store.add({ name: 'myke', badjorance: 'game' });
store.add({ name: 'grey', badjorance: 'honor' });
store.add({ name: 'grey', badjorance: 'incognito' });
store.add({ name: 'grey', badjorance: 'joke' });
store.add({ name: 'grey', badjorance: 'key' });
store.add({ name: 'grey', badjorance: 'lemon' });
store.add({ name: 'brady', badjorance: 'mast' });
store.add({ name: 'brady', badjorance: 'nothing' });
store.add({ name: 'brady', badjorance: 'opera' });
store.add({ name: 'brady', badjorance: 'pear' });
store.add({ name: 'brady', badjorance: 'quote' });
store.add({ name: 'brady', badjorance: 'rodent' });
store.add({ name: 'brady', badjorance: 'sunk' });
database.close();
var openRequest = indexedDB.open('test-db');
openRequest.onerror = function (errorEvent) { console.log('open error', errorEvent); };
openRequest.onblocked = function (blockedEvent) { console.log('open blocked', blockedEvent); };
openRequest.onsuccess = function (successEvent) {
console.log('Store filled');
var database = successEvent.target.result;
var transaction = database.transaction('sochrastic', 'readonly');
var store = transaction.objectStore('sochrastic');
var indexName = store.index('index_name');
var nameCountRequest = indexName.count();
nameCountRequest.onerror = function (errorEvent) { document.querySelector('#name-id-count').textContent = 'error'; console.log(errorEvent); };
nameCountRequest.onblocked = function (blockedEvent) { document.querySelector('#name-id-count').textContent = 'blocked'; console.log(blockedEvent); };
nameCountRequest.onsuccess = function (successEvent) { document.querySelector('#name-id-count').textContent = successEvent.target.result; console.log('name-id', successEvent.target.result); };
var indexId = store.index('index_id');
var idCountRequest = indexId.count();
idCountRequest.onerror = function (errorEvent) { document.querySelector('#id-count').textContent = 'error'; console.log(errorEvent); };
idCountRequest.onblocked = function (blockedEvent) { document.querySelector('#id-count').textContent = 'blocked'; console.log(blockedEvent); };
idCountRequest.onsuccess = function (successEvent) { document.querySelector('#id-count').textContent = successEvent.target.result; console.log('id', successEvent.target.result); };
}
}
}
}
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>IndexedDB Indices</title>
</head>
<body>
<p>['id', 'name'] index result: <span id="name-id-count"></span></p>
<p>['id'] index result: <span id="id-count"></span></p>
</body>
</html>
IE 和 Edge 根本不支持复杂索引https://developer.microsoft.com/en-us/microsoft-edge/platform/status/indexeddbarraysandmultientrysupport/?q=indexeddb,但您可以在其他浏览器中使用它们。
If I change the creation of the complex index from ['id', 'name'] to the (according to the spec) equivalent id.name, Safari changes behaviour to simple: 19, complex: 0, the others remain the same.
它们并不等同。 id.name
在单个值上创建索引,如 {id: {name: 'value'}}
,['id', 'name']
在两个字段上创建复合索引,如 {id: 1, name: 'value'}
.
您的索引失败是因为您依赖于自动生成的主键 id
。如果您将 id
更改为 badjorance
,那么您的计数符合您的预期,至少在 Firefox 和 Chrome 中是这样。 (顺便说一句,即使在您的原始示例中,我也没有看到任何区别,两种浏览器都显示为 0)。
我猜有些浏览器会在将主键添加到对象之前评估 keyPath,而其他浏览器会在之后评估。至于哪种行为是正确的……我想阅读规范已经很晚了,但是除非规范不明确,否则您可能想报告浏览器中的错误。如果我是赌徒,我猜 Safari 是错误的。