Способ создания индекса indexedDB в IDBObjectSore с помощью keyPath, например: 'location: location._id' - PullRequest
0 голосов
/ 17 февраля 2020

У меня есть некоторые данные в хранилище indexedDB, которое выглядит следующим образом:

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

Я хотел бы создать индекс для _id внутри этого местоположения, но кажется, что indexedDB не нравится это двоеточие между местоположением: местоположение. Я получаю сообщение об ошибке: DOMException: не удалось выполнить 'createIndex' для 'IDBObjectStore': аргумент keyPath содержит неверный путь к ключу

Двоеточие - это соглашение, которое используется тысячами и тысячи строк кода, поэтому просто изменить его было бы проблемой. Есть ли способ обойти это? Например, как убежать от двоеточия?

1 Ответ

2 голосов
/ 17 февраля 2020

Глядя на https://www.w3.org/TR/IndexedDB-2/#key -path-construct Я вижу, что в нем говорится:

Допустимый путь ключа - один из:

  • Пустая строка.
  • Идентификатор, который представляет собой строку, соответствующую продукции IdentifierName из спецификации языка ECMAScript [ECMA-262].
  • Строка, состоящая из двух или более идентификаторов, разделенных точками (U + 002E FULL STOP).
  • Непустой список, содержащий только строки, соответствующие указанным выше требованиям.

Пробелы в ключевом пути запрещены.

Похоже, что двоеточие нарушает вторую точку маркера.

Можно ли изменить данные в том виде, в каком они записаны и прочитаны из базы данных? Это довольно распространенная вещь, возникающая при хранении данных, иногда вам нужно изменить то, что на самом деле сохраняется.

Что-то вроде:

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);
    };
  });
}

...