2017-05-06 22 views
0

在給Dexie(David Fahlander)的作者發送電子郵件後,我被重定向到此處。這是我的問題:如何使用滾動緩衝區添加到dexie條目(用於存儲大條目而不分配GB內存)

有沒有辦法追加到現有的Dexie條目?我需要存儲dexie中很大的東西,但我希望能夠使用滾動緩衝區填充較大的條目,而不是分配一個巨大的緩衝區,然後再創建一個商店。

例如,我有一個2gb文件,我想以dexie存儲。我想通過將32kb一次存儲到同一商店來存儲該文件,而無需在瀏覽器中分配2GB內存。有沒有辦法做到這一點? put方法似乎只覆蓋條目。

回答

1

感謝您將您的問題放在這裏在stackoverflow :)這有助於我建立一個開放的知識基礎,爲每個人訪問。

在沒有實例化整個條目的情況下,IndexedDB沒有辦法更新條目。 Dexie添加了update()和modify()方法,但它們只是模擬一種方法來改變某些屬性。在後臺,整個文檔將總是暫時加載到內存中。

IndexedDB也具有Blob支持,但是當存儲在IndexedDB中的Blob中,其整個內容通過規範被克隆/複製到數據庫中。

因此,處理這個問題的最佳方法是爲動態大內容分配一個表併爲其添加新條目。

例如,假設您有一個表「files」和「fileChunks」。您需要不斷增加「文件」,並且每次執行此操作時,都不希望在內存中實例化整個文件。然後,您可以將文件塊作爲單獨的條目添加到fileChunks表中。

let db = new Dexie('filedb'); 
db.version(1).stores({ 
    files: '++id, name', 
    fileChunks: '++id, fileId' 
}); 

/** Returns a Promise with ID of the created file */ 
function createFile (name) { 
    return db.files.add({name}); 
} 

/** Appends contents to the file */ 
function appendFileContent (fileId, contentToAppend) { 
    return db.fileChunks.add ({fileId, chunk: contentToAppend}); 
} 

/** Read entire file */ 
function readEntireFile (fileId) { 
    return db.fileChunks.where('fileId').equals(fileId).toArray() 
    .then(entries => { 
     return entries.map(entry=>entry.chunk) 
      .join(''); // join = Assume chunks are strings 
    }); 
} 

夠簡單。如果你想appendFileContent是滾動緩衝器(用最大的尺寸和擦除舊的內容),您可以添加截斷方法:

function deleteOldChunks (fileId, maxAllowedChunks) { 
    return db.fileChunks.where('fileId').equals(fileId); 
     .reverse() // Important, so that we delete old chunks 
     .offset(maxAllowedChunks) // offset = skip 
     .delete(); // Deletes all records older before N last records 
} 

你會得到其他好處,如能夠到尾存儲文件沒有它的全部內容加載到內存中:

/** Tail a file. This function only shows an example on how 
* dynamic the data is stored and that file tailing would be 
* simple to do. */ 
function tailFile (fileId, maxLines) { 
    let result = [], numNewlines = 0; 
    return db.fileChunks.where('fileId').equals(fileId) 
     .reverse() 
     .until(() => numNewLines >= maxLines) 
     .each(entry => { 
      result.unshift(entry.chunk); 
      numNewlines += (entry.chunk.match(/\n/g) || []).length; 
     }) 
    .then (()=> { 
     let lines = result.join('').split('\n') 
      .slice(1); // First line may be cut off 
     let overflowLines = lines.length - maxLines; 
     return (overflowLines > 0 ? 
      lines.slice(overflowLines) : 
      lines).join('\n'); 
    }); 
} 

我知道塊會在readEntireFile()和tailFile(正確的順序的原因)是IndexedDB的查詢將永遠的順序進行檢索,查詢列主要,但次要按主鍵的順序,這是自動遞增的數字。

這種模式可以用於其他情況下,如日誌記錄等。如果文件不是基於字符串的,你將不得不稍微改變這個例子。具體來說,不要使用string.join()或array.split()。

+0

謝謝你的回覆!我試圖加註你,但由於它是一個新帳戶,所以不會因爲限制而讓我。這就是說,這也是我曾經想到的。基本上只是將文件分塊併爲每個塊添加記錄。我不知道我將如何實現它,但您提供的代碼回答了這個問題。感謝一羣人。愛dexie到目前爲止!我使用它與libmicrohttpd和一個自定義websocket實現,它就像開發一個實際的客戶端應用程序(而不是一個典型的JavaScript應用程序)。愛它! –

+0

謝謝!我更新瞭如何使用滾動緩衝區(截斷舊內容)的答案, –

相關問題