根据索引在IndexedDB中删除多个记录

19

我正在使用 IndexedDB,有两个对象仓库:equip(表示不同的设备,主键为tagNo),和equipParts(表示一件设备的部件,并且具有基于标记号/序列号的索引,主键seqNo,其中的一个字段tagNo表示该部件所属的设备)。

如果我删除equip中的记录,则希望删除所有在equipParts中具有equiptagNo的记录(就像“where equipParts.tagNo = equip.tagNo”一样)。

来自我的代码摘录:

var tx = db.transaction(["equip", "equipParts"],"readwrite");
var estore = tx.objectStore("equip");
var pstore = tx.objectStore("equipParts");
var tagIndex = pstore.index("by_tagNo");
var pdestroy = tagIndex.openCursor(IDBKeyRange.only(tagno)); //opens all records bearing the selected tag number
pdestroy.onsuccess = function() {
    var cursor = pdestroy.result;
    if (cursor) {
        if (cursor.value.tagNo == tagno) {
            pstore.delete(cursor.value.seqNo); //I guess I'm wrong here
        }
        cursor.continue;
    }
}
pdestroy.onerror = function() {
    alert("Deletion attempt NG");
}
var ereq = estore.delete(tagno);
ereq.onsuccess = function(e) {
    alert("Form deletion OK");
    window.location = "index.html";
}
ereq.onerror = function(e) {
    alert("Form deletion NG");
    window.location = "index.html";
}
db.close();
问题在于仅删除了equip中的记录,而equipParts中的记录仍然存在。是否有一种方法可以根据非唯一索引(可以是父对象存储区的主键)删除IndexedDB对象存储区中的多个记录?
3个回答

22

你必须获取主键才能删除记录。

var pdestroy = tagIndex.openKeyCursor(IDBKeyRange.only(tagno)); 
pdestroy.onsuccess = function() {
  var cursor = pdestroy.result;
  if (cursor) {
      pstore.delete(cursor.primaryKey);
      cursor.continue();
  }
}

或者,但不够高效

var pdestroy = tagIndex.openCursor(IDBKeyRange.only(tagno)); 
pdestroy.onsuccess = function() {
  var cursor = pdestroy.result;
  if (cursor) {
      cursor.delete();
      cursor.continue();
  }
}

1
第二个为什么不高效? - Frank Schwieterman
3
openCursor 返回 IDBCursorWithValue,需要读取记录值,而第一个返回 IDBCursor 不包含记录值。 - Kyaw Tun
1
谢谢。但只有后者在同一事务中执行完整的删除,这是真的吗? - Frank Schwieterman
4
在Safari上,当游标打开时删除记录会出现错误。即使存在其他匹配记录,游标也会变成 null。更可靠的方法是获取所有主键,然后对每个主键调用 IDBObjectStore.delete() 进行删除。 - cleong
1
@datdinhquoc 你说得对,它会创建一个新的请求,但使用相同的源,因此它将调用相同的onsuccess回调函数,其中调用了continue - Kyaw Tun
显示剩余4条评论

2

我使用 idb 这种方式删除了属于一个索引的多条记录:

    var tx = idb.transaction("MyObjectStore", 'readwrite');
    var index = tx.store.index('my_relid_idx');
    var pdestroy = index.openCursor(RelID);
    pdestroy.then(async cursor => {
        while (cursor) {
            cursor.delete();
            cursor = await cursor.continue();
        }
    })

这是使用jakearchibald/idb,而不是原始的IndexedDB API。 - Dee

1
我发现了一种最简单的方法,使用以下代码:

index.iterateCursor(IDBKeyRange, (cursor) => {
  if(cursor){
    cursor.delete();
    cursor.continue();
  }
});

那样的话,如果您将其放在异步函数下面,您只需使用

即可。
await index.iterateCursor...

等待另一端的 Promise


这个可以工作,但为什么IDBIndex下面不能直接有一个“delete”方法,就像.get和.getAll一样呢? - Dee
更新:我在IDBIndex文档中找不到iterateCursor方法;我已经尝试过了,它不起作用@sebas。 - Dee
.iterateCursor 看起来是一个旧特性吗?:https://github.com/jakearchibald/idb/search?q=iterateCursor - Dee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接