2013-01-21 10 views
10

Przechowuję dużą liczbę małych obiektów w IndexedDB. Chciałbym umożliwić użytkownikowi wyeksportowanie jednego ze sklepów obiektów do pliku, który może "pobrać".Jak mogę umożliwić użytkownikom wydajne zapisywanie zawartości magazynu obiektów indeksowanych DB do pliku?

Przeczytałem this blog article. Co oznacza czytanie danych, kodowanie ich przy pomocy encodeURIComponent i umieszczanie ich jako href dla łącza, z którego mogą pobrać dane. Coś takiego:

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

To jest w porządku, z wyjątkiem sklepu obiekt będzie mieć miliony rekordów i nie czuję, że to będzie wystarczająco wydajna. Czy istnieje sposób, aby bardziej bezpośrednio umożliwić użytkownikowi zapisanie składnicy obiektów jako pliku (w sposób, który mogę ponownie zaimportować za pośrednictwem strony internetowej).


Edit Od niektórych notatek w komentarzach przepisał mi trochę o tym, jak to działa, aby uzyskać trochę więcej soku z niego. Nowy kod jest podobny do:

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

które dadzą mi wyniki jak:

  • zapisów 10k, 975.87ms średni czas eksport
  • 100k rekordów, 5,850.10ms czas średni eksportowej
  • 1mil rekordy, 56 681,00ms średni czas eksportu:

Jak widać, milion rekordów zajmuje około minuty t. Czy istnieje lepszy sposób na robienie tego? (Próbowałem też użyć kursora zamiast .getAll(), ale kursory są wolniejsze)

+0

Chcę powiedzieć: "użyj localStorage dla zasobu aktualnie oglądanego (i do zapisywania/ładowania), i umieść DB w WebWorker", ale mam wrażenie, że nawet to nie wpłynęłoby zbytnio na wydajność. –

+0

Tak, myślałem o zrobieniu ładowania i serializacji od webworkera, ale wciąż musi być serializowane przez przeglądarkę, aby wrócić; które moim zdaniem przyniosą taki sam wynik. Jeśli chodzi o lokalną pamięć masową, nie sądzę, że umieszczenie 3 milionów obiektów + jest dobrym pomysłem ... – Chad

+0

czy spróbowałeś? wydostanie się z 3 milionów obiektów z IndexedDB powinno zająć tylko kilka sekund. Tworzenie pliku poprzez 'window.URL.createObjectURL (new Blob (content, {'type': MIME_TYPE}))' powinno być w porządku. –

Odpowiedz

1

IDBObjectStore.getAll nie jest częścią standardu IndexedDB i używa kursora pod kołdrą.

Uwaga: Mozilla wdrożyła GETALL(), aby obsłużyć tę sprawę (i getAllKeys(), która jest obecnie ukryty za dom.indexedDB.experimental preferencji w about: config). nie są one częścią standardu IndexedDB, więc mogą zniknąć w przyszłości. Mamy uwzględniono je, ponieważ uważamy, że są przydatne. Poniższy kod nie dokładnie to samo, co powyżej:

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

Jest wydajność koszt związany z patrzenia na własność kursora wartość , ponieważ obiekt jest tworzony leniwie. Gdy użyjesz na przykład metody getAll(), Gecko musi utworzyć wszystkie obiekty naraz. Jeśli interesuje Cię tylko przeglądanie każdego z kluczy, dla instancji znacznie efektywniej jest używać kursora niż używać getAll(). Jeśli jednak chcesz uzyskać tablicę wszystkich obiektów w magazynie obiektów , użyj funkcji getAll().

Jedynym sposobem na pobranie rekordów, w których nie znasz klucza, jest użycie kursora. Więc nie sądzę, że istnieje lepszy sposób. Ale musisz zadać sobie pytanie, czy jest to szybsze niż pobieranie rekordów z serwera.

+0

To prawda, ale to nie odpowiada na pierwotne pytanie, jaki jest najszybszy sposób na osiągnięcie tego, co chcę zrobić. – Chad

+0

Wierzę, że istnieje tylko jeden sposób. Nie widzę żadnych innych opcji w interfejsie API. – denov

+2

Prawidłowo, jest to aplikacja offline, więc nie ma serwera. 'getAll' było rozwiązaniem, z którego korzystałem, naprawdę chciałem sprawdzić, czy jest coś jeszcze. – Chad

Powiązane problemy