TypeScript+大量CSVと格闘したお話
なぜあんな格闘したんだろう
みなさんどうも、jey_desunですん
今日はTypeScriptで大量のCSVを捌くのにすげー格闘したお話をお届けします。
事の発端
長年サービスを開発/運用していると、どうしてもみたいなことが出てくる事、よくありますよね。
今回は、百万行あるCSVを1行ずつ加工して、データベースに保存しなければいけなくなったというお話です。
読み込み
まぁ、読み込むのはちゃちゃっとテキトーにできました
↓ちょっと適当ですけどこんな感じ
import {GetObjectCommand, S3Client} from '@aws-sdk/client-s3'
const s3 = new S3Client({
region: 'ap-northeast-1'
});
const result = await s3.send(
new GetObjectCommand({
Bucket: 'Bucket',
Key: 'Key'
})
);
const stream = result.Body as Readable;
※aws-sdkのv3
何にハマったか
今回はCSVでsjisで〜みたいな感じだったので、pipeでparseしたりdecodeしたりしてdata
イベントでどうにかしたりと。
stream.pipe(parse({encoding: 'sjis-win'}))
.pipe(decode(data,))
.on('data', data => {
logger.debug(data);
});
ここで、問題になったのは、1行ずつDBに入れるのはかなり負荷になってしまうので、1000件ずつくらいにまとめてバルクインサートしたかった。
あと、並々ならぬ理由で処理の終わりを待ちたかった。
しかし、この書き方だと並列処理なので全然うまくいかない
end
イベントでどうにかしようとしてもendイベントももちろんdata
の終わりなんて待たない?のでちょー速攻で発火される(もしかしたらここで別のやり方あるのかもしれない)
と、なんかすげー格闘してうまくいかんなぁと。
むっちゃ記事でてくるじゃん
結果辿りついたのはfor-await-of
むちゃ簡単やん。。。むちゃ記事でてくるじゃん。。。
結局
今回は、速度はそこまで気にしなくていいので、1行ずつ待ってくれるfor-await-of
がすごいマッチした
import {GetObjectCommand, S3Client} from '@aws-sdk/client-s3'
import iconv from "iconv-lite";
import {parse} from "csv-parse/sync";
async execute() {
const s3 = new S3Client({
region: 'ap-northeast-1'
});
const result = await s3.send(
new GetObjectCommand({
Bucket: 'Bucket',
Key: 'Key'
})
);
const stream = result.Body as Readable;
const readline = createInterface(stream.pipe(iconv.decodeStream('cp932'))); // 文字コード変換
for await (const line of readline) {
console.log("line = " + line);
}
}
Author And Source
この問題について(TypeScript+大量CSVと格闘したお話), 我々は、より多くの情報をここで見つけました https://zenn.dev/jey_desun/articles/e851695f527561著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Collection and Share based on the CC protocol