2013-01-21 6 views
10

Sto memorizzando una grande quantità di piccoli oggetti in IndexedDB. Vorrei dare all'utente la possibilità di esportare uno degli archivi oggetti in un file che possono "scaricare".Come posso consentire agli utenti di salvare in modo efficiente il contenuto di un archivio oggetti indicizzato DB in un file?

Ho letto this blog article. Che descrive la lettura dei dati, JSON.stringify i dati, codificandolo con encodeURIComponent e ponendolo come href per un collegamento che possono utilizzare per scaricare i dati. Qualcosa di simile a questo:

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

Questo è bene, tranne il negozio oggetto avrà milioni di dischi e non mi sento che questo sarà sufficiente performante. C'è un modo per consentire più direttamente all'utente di salvare un archivio oggetti come file (in un modo che posso importare di nuovo tramite la pagina web).


Modifica Da alcune note nei commenti ho riscritto un po 'di come funziona, al fine di ottenere un po' più succo fuori di esso. Il nuovo codice è simile a:

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

che darà i risultati come:

  • record 10k, 975.87ms tempo medio di esportazione
  • 100k record, 5,850.10ms tempo all'esportazione medio
  • 1mil record, 56.681.00 ms tempo medio di esportazione

Come si può vedere 1 milione di record richiede circa un minuto per esportare t. C'è un modo migliore per farlo? (Ho anche provato a usare un cursore invece di .getAll(), ma i cursori sono più lenti)

+0

Voglio dire "utilizzare localStorage per la risorsa attualmente visualizzata (e per il salvataggio/caricamento) e inserire il DB in un WebWorker", ma mi sembra che anche quello non farebbe molto per le prestazioni. –

+0

Sì, ho pensato di eseguire il caricamento e la serializzazione dal webworker, ma deve ancora essere serializzato dal browser per tornare indietro; che penso prenda lo stesso successo in termini di prestazioni. Per quanto riguarda la memorizzazione locale, non penso che mettere 3 milioni di oggetti + sia una buona idea ... – Chad

+0

hai provato? ottenere da 3 milioni di oggetti da IndexedDB dovrebbe richiedere solo pochi secondi. Costruire il file tramite 'window.URL.createObjectURL (il nuovo Blob (contenuto, {'tipo': MIME_TYPE}))' dovrebbe andare bene. –

risposta

1

IDBObjectStore.getAll non fa parte dello standard IndexedDB e utilizza un cursore sotto le copertine.

Nota: Mozilla ha inoltre implementato getAll() per gestire questo caso (e getAllKeys(), che è attualmente nascosto dietro il preferenza dom.indexedDB.experimental in about: config). questi non sono parte dello standard IndexedDB, quindi potrebbero scomparire in futuro. Abbiamo incluso perché pensiamo che siano utili. Il seguente codice fa esattamente la stessa cosa come sopra:

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

C'è un costo delle prestazioni associato a guardare la proprietà value di un cursore, perché l'oggetto viene creato pigramente. Quando si usa getAll() per esempio, Gecko deve creare tutti gli oggetti contemporaneamente. Se si è interessati solo a esaminare ciascuno dei tasti, per l'istanza , è molto più efficiente utilizzare un cursore che usare getAll(). Se stai cercando di ottenere una matrice di tutti gli oggetti in un archivio oggetti , usa getAll().

L'unico modo per recuperare i record in cui non si conosce la chiave è utilizzare un cursore. Quindi no, non penso che ci sia un modo migliore. Ma è necessario chiedersi se è più veloce di recuperare i record da un server.

+0

Vero, ma questo non risponde alla domanda originale di quale sia il modo più veloce per ottenere ciò che voglio fare. – Chad

+0

Credo che ci sia solo una strada. Non vedo altre opzioni nell'API. – denov

+2

Corretto, questa è un'applicazione offline, quindi non c'è un server. 'getAll' era la soluzione che stavo usando, stavo davvero cercando di vedere se c'era qualcos'altro. – Chad