Как я могу разрешить пользователям эффективно сохранять содержимое хранилища объектов indexedDB в файл?

Я храню большое количество небольших объектов в IndexedDB. Я хотел бы предоставить пользователю возможность экспортировать один из хранилищ объектов в файл, который они могут "загрузить".

Я прочитал эту статью в блоге. Который описывает чтение данных, JSON.stringify ввод данных, кодирование его с помощью encodeURIComponent и размещение его как href для ссылки, которую они могут использовать для загрузки данных. Что-то вроде этого:

var transaction = db.transaction([objectstore], "readonly");
var content = [];
var objectStore = transaction.objectStore(objectstore);

objectStore.openCursor().onsuccess = function(event) {
    var cursor = event.target.result;
    if (cursor) {
        content.push({key:cursor.key,value:cursor.value});
        cursor.continue();
    }
}; 

transaction.oncomplete = function(event) {
    var serializedData = JSON.stringify(dataToStore);
    link.attr("href",'data:Application/octet-stream,'+encodeURIComponent(serializedData));
    link.trigger("click");
};

Это хорошо, за исключением того, что в хранилище объектов будут миллионы записей, и я не чувствую, что это будет достаточно эффективно. Есть ли способ более прямо разрешить пользователю сохранять хранилище объектов в виде файла (таким образом, я могу снова импортировать его через веб-страницу).


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

var transaction = db.transaction([objectstore], "readonly");
var objectStore = transaction.objectStore(objectstore);

objectStore.getAll().onsuccess = function(evt) {
    var url = window.URL.createObjectURL(new Blob(evt.target.results, {'type': 'application/octet-stream'}));
    link.attr('href', url);
    link.trigger('click');
};

Который даст мне результаты, такие как:

  • 10 тыс. записей, среднее время экспорта 975,87 м.
  • 100 тыс. записей, среднее время экспорта 5 850,100 м.
  • 1mil records, 56,681.00ms среднее время экспорта

Как вы можете видеть, 1 миллион записей занимает около минуты, чтобы экспортировать. Есть ли лучший способ сделать это? (Я также попытался использовать курсор вместо .getAll(), но курсоры медленнее)

Ответ 1

IDBObjectStore.getAll не является частью стандарта IndexedDB и использует курсор под обложками.

Примечание. Mozilla также реализовала getAll() для обработки этого случая (и getAllKeys(), который в настоящее время скрыт за dom.indexedDB.experimental предпочтение в about: config). это не часть стандарта IndexedDB, поэтому могут исчезнуть в будущем. У нас включили их, потому что мы считаем, что они полезны. Следующий код точно так же, как и выше:

objectStore.getAll().onsuccess = function(event) {
  alert("Got all customers: " + event.target.result);
};

Существует стоимость производительности, связанная с оценкой стоимости свойство курсора, потому что объект создается лениво. Когда ты Например, используйте getAll(), Gecko должен сразу создать все объекты. Если вам просто интересно посмотреть на каждый из ключей, Например, гораздо эффективнее использовать курсор, чем использовать получить все(). Если вы пытаетесь получить массив всех объектов в однако, используйте getAll().

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