我应该如何批量上传到s3,并通过最终callback从nodeJS webserver插入到MongoDB?

我有一个Web服务器,接受来自客户端的图像,处理它们,将它们上传到S3,批量插入到我的mongoDB,最后发送到客户端的JSON结果。

使用单个图像的工作如下:

router.post("/upload", function(req, res){ var form = new multiparty.Form(); form.parse(req,function(err,fields,files){ s3.upload({ Key: filename, Bucket: bucketname, ACL: "public-read", Body: fs.createReadStream(filepath) }, function(err, data){ if(err) //error handle Model.collection.insert({"name": "name", "url" : data.Location}, function(err, result){ if(err) //error handle res.json({result: result}) }) }) }) }) 

这工作得很好,因为我简单地上传文件数据到s3 – >完成后,插入s3的输出(url)到数据库 – >完成后,将mongo的结果作为jsonarray发送到客户端。

问题是 – 我的客户端HTML除了多个type=fileinput相同的name=images ,以便我可以在我的表单parsing器中访问它们作为images[i] 。 上述algorithm重复images.length次。 当我不得不等待所有的asynchronousS3上传 – > mongo插入完成,我不得不把这个jsonarray结果返回给客户端时,问题会上升,我不能确定这个工作的callback方式和方式。

我试过的是以下几点:

  • 遍历图像,首先将它们上传到S3,用生成的url( [data.Location] )填充数组。 批量插入到mongoDB,并在callback中将jsonarray结果返回给客户端。 这是因为mongo插入不等待S3上传不起作用。
  • 迭代通过图像,上传和插入图像到S3和mongoDB每次迭代。 if (currentIndex = images.length) ,则返回jsonarray结果。 这不能准确地工作,因为我不知道哪些图像将最后结束(不同的大小)。

我应该如何devisealgorithm批量上传s3,批量插入到mongo,返回结果包括S3 URL,文件名等回到客户端作为jsonarray?

提前致谢!

我通常用Promises来解决这类问题,参见: Bluebird 。

然后你可以使用Promise.all()在S3上进行批量上传,一旦你得到callback,你可以批量插入到Mongo中,完成后,运行最后一个callback。 或者,你可以做一个批处理,做两件事: upload->insert to mongo ,当所有这些都完成后,返回最后的callback。 这将取决于您的服务器和一次上传多less个文件。 您也可以使用Promise.map()concurrency选项设置为您要运行的任何并发任务。

伪代码示例:

让asume getFilesuploadFileuploadToMongo返回一个Promise对象。

 var maxConcurrency = 10; getFiles() .map(function(file){ return uploadFile(file) .then(uploadToMongo) },{concurrency: maxConcurrency}) .then(function(){ return finalCallback(); }).catch(handleError); 

例如,如何手动 “promisify * S3:

 function uploadMyFile(filename, filepath, bucketname) { return new Promise(function(resolve, reject){ s3.upload({ Key: filename, Bucket: bucketname, ACL: "public-read", Body: fs.createReadStream(filepath) }, function(err, data){ //This err will get to the "catch" statement. if (err) return reject(err); // Handle success and eventually call: return resolve(data); }); }); } 

你可以使用这个:

 uploadMyFile .then(handleSuccess) .catch(handleFailure); 

所有漂亮和漂亮!

如果你不能承诺工作,你可以将你的通话状态存储在一个局部variables中。 您只需将呼叫分成两个function,一个上传和一个批量上传。

这是肮脏的代码,但你应该能够得到这个想法:

 router.post("/upload", function(req, res){ var form = new multiparty.Form(); form.parse(req,function(err,fields,files){ if (err){ cb(err); } else { bulkUpload(files, fields, function(err, result){ if (err){ cb(err); } else { res.json({result:result}); } }) } }) }) function singleUpload(file, field, cb){ s3.upload({ Key: filename, Bucket: bucketname, ACL: "public-read", Body: fs.createReadStream(filepath) }, function(err, data){ if(err) cb(err); } else { Model.collection.insert({"name": "name", "url" : data.Location}, function(err, result){ if(err){ cb(err); } else { cb(null, result); } }) } }) } function bulkUpload (files, fields, cb) { var count = files.length; var successes = 0; var errors = 0; for (i=0;i<files.length;i++) { singleUpload(files[i], fields[i], function (err, res) { if (err) { errors++ //do something with the error? } else { successes++ //do something with the result? } //when you have worked through all of the files, call the final callback if ((successes + errors) >= count) { cb( null, { successes:successes, errors:errors } ) } }); } } 

这不会是我推荐的方法,但另一个用户已经提出了承诺。 我认为一种替代方法会更有帮助。

祝你好运!