前回は、ファイルのダウンロードだったけど、今回はアップロード。
アップロードの場合、フォームをpostするのに、enctype=’multipart/form-data’とする必要があるが、node.js初心者のため、まずはここの処理でつまずいた。
ASP.netなんかだと、IFormFileなどで、簡単にファイルを切り出せるけど、node.jsではサードパーティ製のフィルタ(?)を使用する必要があるようだ。一番一般的に使われているのはmulterというものらしい。post時にこのフィルタを指定すると、ファイル以外のフィールド値とファイルを取得できる。
<form method="post" enctype="multipart/form-data">
タイトル:<input type="text" name="title"/>
ファイル:<input type="file" name="upfile"/>
<input type="submit" value="アップロード"/>
</form>
var router = express.Router();
var multer = require('multer');
var upload = new multer();
var mongo = require('mongodb');
var buffer = require('buffer');
router.post('/', upload.any(), async (req,res,next) => {
// fieldとファイルを取得
const { fld , files } = req;
var title = fld['title'];
var upfile = files[0];
・・・
ちなみに、upfile(=files[0])の内容は以下のような感じ。
{
fieldname: 'upfile',
originalname: 'ファイル名.タイプ',
encoding: '7bit',
mimetype: 'image/png',
buffer: <Buffer 89 50 4e ... 5926 more bytes>,
size: 5976
}
これをMongoDbのGridFSにアップロードしたいのだが、やはりダウンロードと同じく、非同期しかサポートされていないので、以下のような関数を定義した。
await cli.connect();
let db = cli.db('DBName');
let fs = new mongo.GridFSBucket(db);
let stm = fs.openUploadStream(upfile.originalname);
let fileid = await WriteAsync(stm,upfile.buffer);
・・・
//
// GridFSへの書き込み(同期っぽく見えるようにしてみた)
//
async function WriteAsync(stm,data) {
return new Promise((resolve,reject) => {
try {
// end()を呼ぶとfinishイベントが発生
stm.on('finish',()=>{
resolve(stm.id);
});
stm.on('error',()=>{
reject('Write Error');
});
var sts = stm.write(data);
if (!sts) {
reject('Write Error');
}
// これ呼ばないと永遠に終わらない
stm.end();
} catch (err) {
reject(err);
}
});
気を付けないといけないのは、GridFSBucketWriteStream.end()を呼び出さないと、永遠に待ち状態になってしまうところ。
色々と調べたのだが、あまり良い例が載っていなくて苦労した。