node.jsでMongoDB上のGridFSからファイルをダウンロードするのに手間取ったので、メモ。
やりたかったのは、MongoDB上のGridFSからイメージファイルデータを取得して、データURLを作りたかっただけだけど、node.jsのMongoDB DriverのGridFSBucketReadStreamのreadメソッドが、非同期動作しかできないようで、色々苦労した・・・
結局、read周辺の部分をpromiseを使用して、async funcitonにする事でとりあえず、一見落着。
var mongo = require('mongodb');
var buffer = require('buffer');
・・・
let fs = new mongo.GridFSBucket(db);
// ObjectIdを使用してGridFSBucketReadStreamを得る
var stm = fs.openDownloadStream(ObjectId("xxx・・・"));
// 同期的にイメージファイルデータ取得
var body = await ReadAsync(stm);
var imgUrl = 'data:image/jpeg;base64,' + buffer.Buffer.from(body).toString('base64');
//
// GridFSBucketReadStreamから同期的に(見えるように)データ取得
// 戻り値:Promise<Buffer>
//
async function ReadAsync(stm) {
return new Promise((resolve,reject) => {
try {
var totalsize = 0; // 読み取ったトータルサイズ
var chunks = []; // 読み取ったchunk
// データ取得時コールバック定義
stm.on('data',
(v) => {
// 読込んだデータ(chunk)を保存
var buf = buffer.Buffer.from(v);
chunks.push(buf);
totalsize += buf.length;
}
);
// データ終了時コールバック定義
stm.on('end',
() => {
// 結合先のBufferを作成
var ximage = buffer.Buffer.alloc(totalsize);
// 全chunkの結合
var offset = 0;
for(var i=0; i < chunks.length; i++) {
chunks[i].copy(ximage,offset);
offset += chunks[i].length;
}
// 読込んだデータを返す
resolve(ximage);
}
);
// 読込可時コールバック定義
stm.on('readable',
// 読込開始
()=> stm.read()
);
} catch (err) {
reject(err);
}
});
}
解決するまでにちょっと時間が掛かったなぁ・・・
これが正解かどうかは分からないけど、取敢えず動いているからいいや。
正規のライブラリにもawait stm.read()で呼び出させるようなメソッド用意しておいて欲しいな。