諸事情でデータベースに直接バイナリデータを保存する必要が出たのでexpessとsequelizeを使ってやってみました。
スキーマ情報
dataテーブルにfilenameとdataというカラムを作ります。 dataカラムはLONGBLOBを設定しました。
Viewの作成
まずはフォームを作ります。 views/data/new.pug
form(method="POST" enctype="multipart/form-data" action=".")
input(name="filedata" type="file")
input(type="text")
button(type="submit" value="save") 送信
Viewのルーティング
router.get('/data/new', function(req, res, next) {
res.render('data/new');
});
アップロード
受け取ったデータをそのままDBに入れたかったのですが、multipartだと良いライブラリが見つからず、 connect-multipartyを使って一度ファイルに落としたあとfsで読み込んでいます。
const multipart = require('connect-multiparty');
const multipartMiddleware = multipart();
router.post('/data', multipartMiddleware, function(req, res, next) {
const filedata = req.files.filedata;
const data = fs.readFileSync(filedata.path);
db.Data.create({
filename: filedata.originalFilename,
data: data
}).then(()=>{
req.flash('info', 'uploaded');
res.set('Location', '/data');
res.send(301);
}).catch((error)=>{
req.flash('info', 'upload error: ' + error);
res.set('Location', '/data');
res.send(301);
});
});
ダウンロード
Content-Dispositionヘッダーでファイル名を指定してダウンロード時に指定のファイル名になるようにしています。
router.get('/data/:id', function(req, res){
db.Data.findOne({
where: {id: req.params.id}
}, {raw: true}).then((data)=>{
res.set({'Content-Disposition': `attachment; filename="${data.filename}"`});
res.send(data.data);
});
});