node-mysqlで結果一覧をfor await ofで捌くの画像
芽萌丸プログラミング部 @programming
投稿日 2022/07/08

Node.js

node-mysqlで結果一覧をfor await ofで捌く

node-mysqlモジュールを使ったMySQL DBへの問い合わせ結果を for await...of で扱う方法のメモです。

目次:

前提

  • node v16.14.2

  • node-mysql v2.18.1

  • 以下のテスト用テーブルが既に存在すること:

    mysql> select * from hugetable;
    +----+
    | id |
    +----+
    |  1 |
    |  2 |
    |  3 |
    |  4 |
    |  5 |
    |  6 |
    |  7 |
    |  8 |
    |  9 |
    +----+

サンプルコード

これまでのStreamを使った処理pool.query()な部分を AsyncIterator を返すモダンな処理に切り替えて for await...of で利用しています。

(async () => {

  const mysql = require("mysql");
  const { PassThrough } = require("stream");

  const pool = mysql.createPool({
    connectionLimit: 1,
    host: 'localhost',
    user: 'dbuser',
    password: 'dbpass',
    database: 'test',
  });

  const sql = "SELECT * FROM hugetable";

  // AsyncIterableなDB問い合わせ結果を取得
  const ait = pool
    .query(sql)
    .stream()
    .pipe(new PassThrough({ objectMode: true }));

  for await (const row of ait) {
    console.log("row:", row);
    // if (row.id === 3) break; // 途中でbreakすることも可能!
  }

  console.log("finish.");
  pool.end();

})();

/* Console logs:
row: RowDataPacket { id: 1 }
row: RowDataPacket { id: 2 }
row: RowDataPacket { id: 3 }
row: RowDataPacket { id: 4 }
row: RowDataPacket { id: 5 }
row: RowDataPacket { id: 6 }
row: RowDataPacket { id: 7 }
row: RowDataPacket { id: 8 }
row: RowDataPacket { id: 9 }
finish.
*/

メリット

for await of (AsyncIterator) を使うことで、Streamと同様に効率的に大量データを捌けるだけでなく、以下のようなメリットもあります:

  • 中断処理がStreamよりも比較的簡単にコーディングできる
  • Streamの場合よりもイベントループのブロッキングが少ない (筆者の環境でblocked-atを使った調査の結果)

参考

今回使ったサンプルコードはmysqljs/mysql/issues/2192のdougwilsonさんのコメントを参考にさせていただきました。


芽萌丸プログラミング部
芽萌丸プログラミング部 @programming
プログラミング関連アカウント。Web標準技術を中心に書いていきます。フロントエンドからサーバサイドまで JavaScript だけで済ませたい人たちの集いです。記事は主に @TanakaSoftwareLab が担当。