5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Node-REDダッシュボードでファイルをアップロードする

Last updated at Posted at 2023-12-24

Node-REDダッシュボードでファイルをアップロードする

はじめに

Node-REDでファイルをアップロードしたいと思ったことはありませんか。筆者も業務でCSVデータをリレーショナルデータベース(以下DB)に登録する必要があって、Node-REDで簡単に実現できないかなと探したところnode-red-contrib-ui-uploadと関連ライブラリのnode-red-contrib-chunks-to-linesが見つかりました。実際に使って試してみたところ、よく考えられていてCSVデータをDBに登録する場合等に最適のノードと思われたので、ここで紹介してみたいと思います。

早速node-red-contrib-ui-uploadを使ってみる

ファイルのアップロードを行うライブラリがnode-red-contrib-ui-uploadで、uploadノードが含まれています。uploadノードはNode-REDダッシュボードのパーツとして作られているため、利用する場合には事前にnode-red-dashboardを用意する必要があります。また、ダッシュボードを用意してuploadノードを設定する場合、そのグループの幅を12に指定する必要があるようです。デフォルトの6のままでは幅が狭く正しく表示できないので注意してください。

最初に作ったフローはこんな感じでした。

node-red-csv-upload-01.png

見ての通りの単純なもので、uploadノードで受けたCSVデータをcsvノードで1行毎にjsonデータに変換し、それをDBに登録します。

この状態でWebブラウザでダッシュボードにアクセスすると次のように表示されます。

node-red-csv-upload-02.png

参照ボタンを押すとファイル選択のダイアログが開くので、ファイルを選ぶと次のように表示が変わります。右三角のボタンを押せばファイルがアップロードできます。

node-red-csv-upload-03.png

アップロード途中でのキャンセルボタン(右端の四角ボタン)とアップロード中をプログレスバーで表示する機能もあります1

本フローを試してみたところ、1行程度のCSVデータであれば問題無くDBに登録できたのですが、数百行の規模になると全部を正しく登録できずデータに欠損が生じてしまいました。

フロー制御を加えてデータの流れすぎを防ぐ

なぜデータが多くなると正しく登録できなくなったのでしょうか。これはNode-REDがnode.jsで実装されているため、node.jsの非同期の挙動がそのままNode-REDに影響していることが原因です。

一般的にDBへのレコードのインサートはDBの処理の中でも時間のかかるものとなります。node.jsは非同期に動作するため、DB Insertノードの処理でデータの追加に時間がかかると、その完了を待たずにDB Insertノードは次のデータを受け付けてしまいます。CSVデータの各行をjsonに変換したものが次々と大量に送られてくるようなシチュエーションでは、DBへの登録処理が間に合わなくなってデータ登録が欠損します。

もしDB Insertノードでの処理が終わってから次のデータが送りこまれるように改良できれば、このような事態を回避できます。そのためにnode-red-contrib-ui-uploadにはフロー制御の機能が用意してあり、node-red-contrib-chunks-to-lineschunks-to-linesノードを組み合わせて利用する例がドキュメントに記載されています2

chunks-to-linesノードを組み込んで修正したのが次のフローです。

node-red-csv-upload-04.png

最初のフローと比べると、uploadノードとcsvノードの間にchunks-to-linesノードが加わり、DB Insertノードの出力からnext lineというfunctionノードを経由してchunks-to-linesノードにループが出来ています。

chunks-to-linesノードは、uploadノードから送られてくるバイナリデータをフロー制御しながらテキストとして指定行数を切り出して次のノードへ送る機能があります。これによってCSVなどのテキストデータを指定行数(ここでは1行)づつ次のcsvノードに送るようになります。

chunks-to-linesノードが行を切り出して最初の行を出力するのは理解できますが、2行目以降は何をきっかけに出力するのでしょうか。それを行っているのがnext lineのfunctionノードのループです。このfunctionノードの中身はこれだけです。

return { tick: true };

つまりchunks-to-linesノードは{ tick: true }のメッセージを受けると、新たな行を次のノードへ出力する仕様となっているのです。

DB Insertノードで処理が終わるとそのタイミングで出力されるメッセージをきっかけに、next lineのfunctionノードから{ tick: true }のメッセージがchunks-to-linesノードに送られて、それによって次CSVデータが送り出されるループによって、確実に1レコードづつDBへの登録ができるようになります。

chunks-to-linesノードは最終行の出力時にmsg.completeを出力するので、ファイル読み込みの終わりを判断したい場合はmsg.completeがあるかどうかで確認できます。

chunks-to-linesノードの挙動を理解する

chunks-to-linesノードの挙動を理解するには、next lineのfunctionノードを使ったループの代わりにinjectノードを使って次のようなフローを作ると、手作業で1個づつデータを登録するテストができてわかりやすいでしょう(実際に筆者はこのようにしてテストを行いました)。

node-red-csv-upload-05.png

node-red-csv-upload-06.png

chunks-to-linesノードの設定

chunks-to-linesノードには次の設定項目が用意されています。

node-red-csv-upload-07.png

node-red-csv-upload-08.png

  • Output n lines at a time : 名前の通りchunks-to-linesノードが一度に送り出す行数です。必要に応じて複数行に設定する場合もあるかもしれませんが、多くの用途では1行の設定で利用するのではないかと思います。
  • Output format : Text, CSV, JSON Arrayから選びます。
    • Text : 元の行をそのまま出力します。
    • CSV : ヘッダ有りのCSVデータを扱う場合に、出力毎にヘッダを繰り返し付加して出力します。
    • JSON Arry : 1行を1要素としたJSON配列に変換して出力します。
  • Text decoding : アップロードデータをどういう文字エンコーディングを前提に扱うかを指定します。UTF-8, Windows-1254(ASCII, ISO-8801), UTF-16, UTF-16LEから選択します。日本語向けのシフトJIS等はありません。

なお、uploadノードにはダッシュボードに必要な項目とノード固有の設定項目がありますが、ノード固有の項目は通常デフォルトで問題無いと思われるのでここでの説明は省略します。

まとめ

uploadノードによってNode-REDダッシュボードにファイルアップロードの機能を追加でき、さらにchunks-to-linesノードを組み合わせることで、CSVデータを1行づつDBに登録するような処理でも問題無く対応できます。

  1. キャンセルボタンやプログレスバーで見る余裕があるほどのアップロードに時間のかかるデータを扱っていないのでこれらの挙動は試せてません。

  2. 最初にドキュメントを読んだ時点でchunks-to-linesノードと組み合わせるところも確認しているのですが、その時点では意味を理解できていませんでした😅

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?