我使用 mongodb使用 multer, gridfs-stream和 mongoose运行express 4,我正在尝试上传文件并将其流式传输到gridfs. 执行此操作的快速路由定义为: app.post('/uploadfile', function (req, res) { console.dir(req.fil
执行此操作的快速路由定义为:
app.post('/uploadfile', function (req, res) { console.dir(req.files); // The mongodb instance created when the mongoose.connection is opened var db = mongoose.connection.db; // The native mongo driver which is used by mongoose var mongoDriver = mongoose.mongo; // Create a gridfs-stream var gfs = new Gridfs(db, mongoDriver); var file = req.files.myFile; var fileId = new ObjectId(); console.log("Creating WriteStream"); var writeStream = gfs.createWriteStream({ _id: fileId, filename: file.originalname, mode: 'w', content_type: file.mimetype, metadata: { id: '123', number: '2', name: "Kenny Erasmuson" } }); console.log("Created WriteStream"); req.pipe(writeStream); console.log("Finished!"); });
快速应用程序运行后,将选择并上载文件(通过HTML multipart / form-data表单),节点服务器的输出为:
$node server.js Listening on port 8001 { myFile: { fieldname: 'myFile', originalname: 'kenny-credit-rating.pdf', name: '1082e5071ede1002c4ae5be6123226d8.pdf', encoding: '7bit', mimetype: 'application/pdf', path: 'uploads/1082e5071ede1002c4ae5be6123226d8.pdf', extension: 'pdf', size: 110782, truncated: false, buffer: null } } Creating WriteStream Created WriteStream Finished! /Users/kenny/Dropbox/Dev/fileUploader/node_modules/mongoose/node_modules/mongodb/lib/mongodb/co nnection/base.js:246 throw message; ^ MongoError: The dollar ($) prefixed field '$conditionalHandlers' in '_id.$conditionalHandlers' is not valid for storage. at Object.toError (/Users/kenny/Dropbox/Dev/fileUploader/node_modules/mongoose/node_modules/mongodb/lib/mongodb/utils.js:114:11) at /Users/kenny/Dropbox/Dev/fileUploader/node_modules/mongoose/node_modules/mongodb/lib/mongodb/collection/core.js:569:27 at /Users/kenny/Dropbox/Dev/fileUploader/node_modules/mongoose/node_modules/mongodb/lib/mongodb/db.js:1157:7 at /Users/kenny/Dropbox/Dev/fileUploader/node_modules/mongoose/node_modules/mongodb/lib/mongodb/db.js:1890:9 at Server.Base._callHandler (/Users/kenny/Dropbox/Dev/fileUploader/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/base.js:448:41) at /Users/kenny/Dropbox/Dev/fileUploader/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js:481:18 at MongoReply.parseBody (/Users/kenny/Dropbox/Dev/fileUploader/node_modules/mongoose/node_modules/mongodb/lib/mongodb/responses/mongo_reply.js:68:5) at null.<anonymous> (/Users/kenny/Dropbox/Dev/fileUploader/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js:439:20) at emit (events.js:95:17) at null.<anonymous> (/Users/kenny/Dropbox/Dev/fileUploader/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/connection_pool.js:201:13)
有没有人有任何想法导致错误和如何解决?
问题在于您没有只将文件请求传递给gridfs-stream.使用Multer作为中间件,捕获任何multipart / form-data post请求.当流进来时,Multer(建于 Busboy)监视on(‘field’)和on(‘file’)事件并相应地解析.你对Multer的管道不仅仅是一个档案.这段代码工作正常,因为Multer确实为你解析了req.files和req.body:
// Create a gridfs-stream var gfs = new Gridfs(db, mongoDriver); var file = req.files.myFile; var fileId = new ObjectId(); console.log("Creating WriteStream"); var writeStream = gfs.createWriteStream({ _id: fileId, filename: file.originalname, mode: 'w', content_type: file.mimetype, metadata: { id: '123', number: '2', name: "Kenny Erasmuson" } }); console.log("Created WriteStream");
但是你的代码遇到问题的地方出于上述原因:
req.pipe(writeStream);
我还没有找到一种方法来流式传输multipart / form-data post请求,而不仅仅是直接将文件上传到GridFS.如果您的发布请求不包含文件以外的任何内容(表示表单中没有其他html输入字段),那么您可能需要考虑至少为此路由从中间件中删除Multer.
对于我的用例,我需要能够接收带有文本输入和文件上传的html表单帖子(我在上传时存储有关文件的元数据).以下是我用Multer完成所需的工作:
var uploadImg = function(req,res) { var writestream = gfs.createWriteStream({ filename: req.files.file.name, mode:'w', content_type:req.files.file.mimetype, metadata:req.body, }); fs.createReadStream(req.files.file.path).pipe(writestream); writestream.on('close', function (file) { res.send("Success!"); fs.unlink(req.files.file.path, function (err) { if (err) console.error("Error: " + err); console.log('successfully deleted : '+ req.files.file.path ); }); }); };
默认情况下,Multer会将您的文件存储在磁盘上.一个快速的解决方案是创建一个读取流并将其直接传输回GridFS.写入完成后,删除tmp文件.
作为旁注,似乎有一些想法,最好只在需要它的路线上使用Multer作为中间件.您可以在this的最后一部分阅读更多有关该想法的内容.
更新
我想我已经接近找到一种方法,通过使用Skipper直接使用元数据直接传输到GridFS.我正在查看是否我不能获得一些更新到skipper-gridfs将采取html表单上的文本输入并将它们设置为元数据等.对于skipper-gridfs的调整似乎很小.当它被刷新时我会更新.如果你看船长,请确保你认识到html表单输入的顺序(如果你有的话)确实很重要.