[Node-RED] フローコンテキストを使ったループ変数を使う

[Node-RED] フローコンテキストを使ったループ変数を使う

こんにちは、 kenzauros です。

Node-RED では基本的にフローが分散して実行されるため、カウンターのようなプログラムチックなことを考える必要はありません。

ただ、バッチ処理のようにデータを順次ループして処理したいこともあります。

そういう場合はフローコンテキストかグローバルコンテキストに値を保持させるのがいいでしょう。今回は change ノードを使ってループ変数のような値を簡単にインクリメントする方法を紹介します。

フローコンテキストとグローバルコンテキスト

Node-RED にはメッセージやノードを横断して使える変数の器として、フローコンテキスト (Flow context)グローバルコンテキスト (Global context) があります。

フローコンテキストの変数は同じフロー内で参照でき、グローバルコンテキストの変数は Node-RED 全体で参照できます。

フローを流れるメッセージ msg だけでなく、こういったコンテキストの変数を使うことで複雑な処理を行えます。

また、巨大なデータを msg に格納したままフローを流すと動作が重くなってしまうことがあるので、フローコンテキストに逃しておく、というような使い方もあります。

以下、フローコンテキストの変数を「フロー変数」、グローバルコンテキストの変数を「グローバル変数」と呼ぶことにします。

フロー変数を使ってみる

とりあえず inject ノード、 change ノード、 debug ノードを下記のように配置・接続します。

フロー変数を使ってみるフロー

フロー変数を使ってみるフロー

inject ノードは特に設定不要です。

フロー変数を初期化するため、 change ノードの msg.flow. に変更して変数名を入力します。ここでは変数名に count、値には数値の 0 を設定します。

フロー変数の初期化

Node-RED フロー変数の初期化

次に debug ノードでこのフロー変数を表示するようにしましょう。「対象」のドロップダウンで JSONata 式を選び $flowContext('count') と入力します。

debug ノードで JSONata 式を指定してフロー変数を表示

debug ノードで JSONata 式を指定してフロー変数を表示

Node-RED の JSONata 機能には $flowContext 関数が用意されており、ここに変数名を渡すことで、フローコンテキストから変数値を取得できます。JSONata 式の詳細は割愛しますので、公式ページ等を参照してください。

この状態でデプロイして、 inject ノードをクリックするとデバッグウィンドウに 0 が表示されるはずです。

フロー変数の内容が表示された

フロー変数の内容が表示された

フロー変数をインクリメントする

さて、これだけではあまり意味がないので、この count フロー変数を操作してみましょう。

実際の処理で使いそうなループを模擬したフローにしてみます。フローに delay ノードと change ノードを追加します。

フローにノードを追加

フローにノードを追加

delay ノードが実際の処理を模擬したノードだと思ってください。遅延時間は適当に設定します(ここでは 1 秒にしました)。

次に、追加した change ノードで count フロー変数をインクリメントするようにしてみます。

初期化時と同じく flow.count を指定します。「対象の値」は $flowContext('count') + 1 とします。

フロー変数のインクリメント

フロー変数のインクリメント

これでフロー変数の count+ 1 したものをフロー変数の count に代入するので、要するに flow.count をインクリメントすることになります。

プログラム言語で言えば flow.count = flow.count + 1 と書いて flow.count++ をしているイメージですね。

この状態でデプロイして、 inject ノードをクリックしてみましょう。1秒に1回、カウントアップされた count が表示されていけば成功です。

フロー変数がインクリメントされている

フロー変数がインクリメントされている

グローバル変数を使う

グローバル変数の場合は change ノードなどで flow. でなく、 global. を選択します。

また、 JSONata 式で使用する場合は $globalContext('count') のように書きます。

ただ、グローバルコンテキストだと、影響範囲が広いので、極力フローコンテキストにとどめておくのがよいと思います。

function ノードでフロー/グローバル変数にアクセスする

もちろん凝ったことをするときは function ノードでもフロー/グローバルコンテキストにアクセスできます。

こちらは下記のようにシンプルです。

フロー変数を取得
const count = flow.get("count");
フロー変数を設定
flow.set("count", 123)

まとめ

今回の例(簡単なカウンター変数)であれば、 msg に格納してままインクリメントしていっても問題ないと思います。

ただ、処理対象のデータセットが大きい場合などは、データセットとカウンターを合わせてフローコンテキストに置いておくことで、処理を軽くできることがあります。

すぐ忘れてしまうので、最後にフローコンテキストとグローバルコンテキストの使い方をまとめておきます。

  フロー グローバル
change ノードなど flow.変数名 global.変数名
JSONata 式 $flowContext('変数名') $globalContext('変数名')
function ノード flow.get("変数名")
flow.set("変数名", 値)
global.get("変数名")
global.set("変数名", 値)

どなたかのお役に立てば幸いです。

参考

kenzauros