
GridFS模塊
首先,特殊道具去tjholowaychuk誰在#node.js的IRC頻道作出回應時,我問,如果任何人有運氣使用GridFS的從貓鼬 。 我得到的很多代碼都來自他與我分享的要旨。 無論如何,到代碼。 我將描述如何使用gridfs,并在完成基礎工作后說明從GridFS流式傳輸文件的過程是如此簡單。
我創建了一個gridfs模塊,該模塊基本上通過mongoose(我在整個應用程序中使用)訪問GridStore,該模塊還可以共享將mongoose連接到mongodb服務器時創建的數據庫連接。
mongoose = require "mongoose"
request = require "request"GridStore = mongoose.mongo.GridStore
Grid = mongoose.mongo.Grid
ObjectID = mongoose.mongo.BSONPure.ObjectID
如果我們不能在mongodb中添加任何文件,我們將無法獲取文件,因此讓我們創建一個putFile操作。
exports.putFile = (path, name, options..., fn) ->db = mongoose.connection.dboptions = parse(options)options.metadata.filename = namenew GridStore(db, name, "w", options).open (err, file) ->return fn(err) if errfile.writeFile path, fnparse = (options) ->opts = {}if options.length > 0opts = options[0]if !opts.metadataopts.metadata = {}opts
實際上,這只是委托給GridStore中存在的putFile操作(作為mongodb模塊的一部分)。 我也有一些邏輯來解析選項,如果沒有提供默認值,則提供默認值。 要注意的一個有趣功能是,我將文件名存儲在元數據中,因為當時我遇到了一個有趣的問題,即從gridFS檢索的文件將id作為文件名(即使在mongo中查看發現文件名實際上是在數據庫)。
現在進行get操作。 此方法的原始實現只是通過調用store.readBuffer()將內容作為緩沖區傳遞給所提供的回調,但是現在已更改為將結果存儲對象傳遞給回調。 其值是調用者可以使用商店對象來訪問元數據,contentType和其他詳細信息。 用戶還可以確定他們想如何讀取文件(進入內存還是使用ReadableStream)。
exports.get = (id, fn) ->db = mongoose.connection.dbid = new ObjectID(id)store = new GridStore(db, id, "r",root: "fs")store.open (err, store) ->return fn(err) if err# band-aidif "#{store.filename}" == "#{store.fileId}" and store.metadata and store.metadata.filenamestore.filename = store.metadata.filenamefn null, store
這段代碼有一個小問題,它檢查文件名和fileId是否相等。 如果是的話,它將檢查是否設置了meta.filename并將store.filename設置為在那里找到的值。 我已經提出了這個問題,以后再進行調查。
該模型
在我的特定實例中,我想將文件附加到模型。 在此示例中,我們假設我們有一個可以附加任意數量文件的應用程序(作業,貸款應用程序等)。 想想稅收收據,完整的申請表以及其他掃描文件。
ApplicationSchema = new mongoose.Schema(name: Stringfiles: [ mongoose.Schema.Mixed ]
)
ApplicationSchema.methods.addFile = (file, options, fn) ->gridfs.putFile file.path, file.filename, options, (err, result) =>@files.push result@save fn
在這里,我將文件定義為混合對象類型的數組(意味著它們可以是任何東西)和方法addFile,該方法基本上采用一個至少包含路徑和文件名屬性的對象。 它使用它來將文件保存到gridfs并將結果的gridstore文件對象存儲在files數組中(其中包含諸如id,uploadDate,contentType,名稱,大小等之類的東西)。
處理要求
所有這些都插入到請求處理程序中,以處理向/ new提交的表單。 所有這一切都需要創建一個Application模型實例,從請求中添加上載的文件(在本例中,我們將文件字段命名為“ file”, 因此命名為req.files.file )并保存它。
app.post "/new", (req, res) ->application = new Application()application.name = req.body.nameopts = content_type: req.files.file.typeapplication.addFile req.files.file, opts, (err, result) ->res.redirect "/"
現在,所有這些工作的總和使我們可以非常輕松地從gridFS下載請求的文件,從而獲得豐厚的回報。
app.get "/file/:id", (req, res) ->gridfs.get req.params.id, (err, file) ->res.header "Content-Type", file.typeres.header "Content-Disposition", "attachment; filename=#{file.filename}"file.stream(true).pipe(res)
在這里,我們只是通過id查找文件,并使用生成的文件對象來設置Content-Type和Content-Disposition字段,最后使用ReadableStream :: pipe將文件寫出到響應對象(這是WritableStream的實例) )。 這是將數據從MongoDB流傳輸到客戶端的魔力。
主意
這只是一個卑微的開始。 其他想法包括將gridfs完全封裝在模型中。 更進一步,我們甚至可以將gridfs模型變成貓鼬插件,以允許完全黑盒使用gridfs。
隨時檢查該項目 ,讓我知道您是否有進一步的想法。 叉開!
參考: 敏捷開發人員博客的Rant and Musings中我們的JCG合作伙伴 James Carr 從MongoDB GridFS流式傳輸文件
翻譯自: https://www.javacodegeeks.com/2012/01/streaming-files-from-mongodb-gridfs.html