使用 keyPath 在 IDBObjectSore 中创建 indexedDB 索引的方法如下:'location:location._id'

Way to create indexedDB index in IDBObjectSore with keyPath like this: 'location:location._id'

我在 indexedDB 存储中有一些数据,如下所示:

{
    "assetNo" : "00045455",
    "location:location" : {
        "title" : "19100003BRMA2879",
        "_id" : "5e2727cbc38a923f5826efb7"
    }
}

我想在该位置内的 _id 上创建一个索引,但 indexedDB 似乎不喜欢 location:location 之间的那个冒号。我收到一个错误: DOMException:无法在 'IDBObjectStore' 上执行 'createIndex':keyPath 参数包含无效的密钥路径

冒号是千行万行代码中使用的约定,所以仅仅更改它就会有问题。有什么办法解决这个问题吗?例如,一种转义冒号的方法?

查看 https://www.w3.org/TR/IndexedDB-2/#key-path-construct 我看到它指出:

A valid key path is one of:

  • An empty string.
  • An identifier, which is a string matching the IdentifierName production from the ECMAScript Language Specification [ECMA-262].
  • A string consisting of two or more identifiers separated by periods (U+002E FULL STOP).
  • A non-empty list containing only strings conforming to the above requirements.

Spaces are not allowed within a key path.

冒号似乎违反了第二个要点。

您可以更改写入数据库和从数据库读取的数据吗?这是存储数据时很常见的事情,有时您需要修改实际持久化的内容。

类似于:

function write(db, object) {
  return new Promise((resolve, reject) => {
    const transaction = db.transaction('mystore', 'readwrite');
    transaction.oncomplete = resolve;
    transaction.onerror = event => reject(event.target.error);
    const store = transaction.objectStore('mystore');

    // what i am suggesting, modify just before write
    // the extra cloning is to avoid side effects on input

    const clone = { ...object };
    clone.location_location = clone['location:location'];
    delete clone['location:location'];

    store.put(clone);    
  });
}

function onupgradeneeded(event) {
  const db = event.target.result;
  const store = db.createObjectStore('mystore');
  db.createIndex('location_id', 'location_location._id');
}

function getByLocationId(db, id) {
  return new Promise((resolve, reject) => {
    const transaction = db.transaction('mystore');
    const store = transaction.objectStore('mystore');
    const index = store.index('location_id');
    const request = index.get(id);
    request.onerror = event => reject(request.error);
    request.onsuccess = event => {
      const result = event.target.result;
      // if we found something, project output as if we stored 
      // it with a colon. we do not need to clone here.
      if (result) {
        result['location:location'] = result.location_location;
        delete result.location_location;
      }
      resolve(result);
    };
  });
}