我应该如何批量上传到 s3 并通过最终回调从 nodeJS 网络服务器插入到 MongoDB?
Posted
技术标签:
【中文标题】我应该如何批量上传到 s3 并通过最终回调从 nodeJS 网络服务器插入到 MongoDB?【英文标题】:How should I batch upload to s3 and insert to MongoDB from nodeJS webserver with a final callback? 【发布时间】:2016-04-03 10:14:19 【问题描述】:我有一个网络服务器,它接受来自客户端的图像,处理它们,将它们上传到 S3,将 url 批量插入到我的 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=file
输入与相同的 name=images
除外,因此我可以在我的表单解析器中以 images[i]
访问它们。上述算法重复images.length
次。当我必须将 jsonarray 结果返回给客户端时,问题就出现了,因为我必须等待所有异步 S3 上传-> mongo 插入完成,而且我无法确定回调将如何以及在哪里完成这项工作.
我尝试过的如下:
遍历图像,首先将它们上传到 S3,使用生成的 url ([data.Location]
) 填充数组。将它们批量插入到 mongoDB 并在回调中将 jsonarray 结果返回给客户端。这不起作用,因为 mongo insert 不等待 S3 上传。
遍历图像,每次迭代上传并插入图像到 S3 和 mongoDB。 if (currentIndex = images.length)
,返回 jsonarray 结果。这不准确,因为我不知道哪些图像会最后结束(不同大小)。
我应该如何设计算法来批量上传s3,批量插入mongo,将包括s3 urls,文件名等的结果作为jsonarray返回给客户端?
谢谢,提前!
【问题讨论】:
【参考方案1】:我通常用 Promises 解决这类问题,见:Bluebird。
然后您可以使用Promise.all()
在 S3 上进行批量上传,一旦您获得该回调,您可以批量插入 Mongo,完成后运行最终回调。或者,你可以做一个批处理来做这两个事情:upload->insert to mongo
,当所有这些都完成后,返回最终回调。这将取决于您的服务器以及您要一次上传多少文件。您还可以使用 Promise.map()
并将 concurrency
选项设置为您想要运行的任何并发任务。
伪代码示例:
假设getFiles
、uploadFile
和uploadToMongo
返回一个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);
一切都好漂亮!
【讨论】:
嗨。事实上,我确实尝试过蓝鸟,但我没有让它运作良好。我跟着我的代码与this guide 相同。代码是过时的还是什么?var s3 = bluebird.promisifyAll(new aws.S3());
似乎没有进行任何更改,bluebird.all(uploadToS3, function(data)uploadToMongo)
也没有等待 s3 上传完成。
经过大量的尝试和尝试,我达到了拥有bluebird.promisify(uploadToS3())
和bluebird.all(mapOfUploadToS3(), function()rest)
的地图的地步。它确实上传到 S3,但现在它永远不会到达其余功能。我怀疑我需要某种机制来让 Promise 知道 uploadToS3() 已经完成了它的工作?我在正确的轨道上吗?
糟糕,抱歉,那是bluebird.join(bluebird.all(mapOfUploadToS3()),function(data)rest);
抱歉,回复的冗长。非常感谢,提前!
我添加了一个关于如何手动完成的示例,我通常这样做是因为我有更多的控制权,我可以记录事情,添加更多的逻辑等等。
谢谢。您的帮助确实帮助我实现了承诺!欣赏它。【参考方案2】:
如果您无法让 Promise 起作用,您可以将调用的状态存储在本地变量中。您只需将调用分解为 2 个函数,一次上传和批量上传。
这是脏代码,但你应该能明白:
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
)
);
这不是我推荐的方法,但是另一个用户已经建议了 promises。我认为另一种方法会更有帮助。
祝你好运!
【讨论】:
以上是关于我应该如何批量上传到 s3 并通过最终回调从 nodeJS 网络服务器插入到 MongoDB?的主要内容,如果未能解决你的问题,请参考以下文章