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