14
11

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 5 years have passed since last update.

Node-RED で遊んでみる第二歩: 配列を加工してみる

Last updated at Posted at 2018-10-27

前回の 第一歩 を投稿した後、以下のようなページや本で学習してみました。

少し周りが見えるようになった第二歩は、配列を加工して遊んでみたいとおもいます。環境は Node-RED v0.19.2です。

なぜ配列か?

フツーのプログラミングだと、配列のように複数の要素を対象にした処理は「ループ」で処理を繰り返すことが多いとおもいます。

あれ Node-RED ってループってあるんだっけ?そもそも複数の値って、ノード間をどうやって流れていくの?と不思議になり、ちょっと試したくなった、ということでネタにしてみました。

フローの新規追加

前回 に作成したフローは一旦忘れて、心機一転、新しいフローを作って始めましょう。

右上のメニューから「フローを新規追加」し、新しく空っぽのフローを作成します。またその下の「フロー名を変更」で適切なフロー名を設定しておきましょう。

image.png

まずはシンプルに

Node-RED で一番シンプルな例は「injectノードと debugノードを並べ、それを接続したもの」のようですね。以下のような感じです。
image.png
これをデプロイした後、フロー画面でinjectノードの以下の部分をクリックすると!
image.png
右にあるデバッグコンソールに、謎の数値 (実はタイムスタンプ値) が表示される、というわけ。
image.png
さて、お約束みたいなので、injectノードの設定を少し変更してみます。ペイロード欄の形式を「文字列」に変更し、適当な文字列 (今回は: Hello Node-RED.) を入力します。また名前を「Hello」に変更しておきましょう。
image.png
名前の変更が反映されたことを確認して、再び「デプロイ」します。
image.png
そしてフロー画面でinjectノードを再びクリックし、デバッグコンソールに指定した文字列がちゃんと出力されていることを確認しましょう。
image.png

配列を出力してみよう

さきほどと同じように、injectノードの設定を変更します。

ペイロード欄の形式に配列は無いようなので「JSON」を選択して、配列データを以下のようなJSON形式で入力します。また名前も一応、「1-5」に変更しています。

[1,2,3,4,5]

image.png
デプロイしてinjectノードをクリックし、ちゃんと配列として出力されていることを確認します。
image.png

それぞれの値を3倍するには

さて、このサンプルをもとに、配列の中の値を3倍する方法を考えましょう。

普通の JavaScript だと、例えばループを使って要素を順に処理する場合は、以下のような感じになりますね。

var list = [1,2,3,4,5];
for (var l=0; l<list.length; l++) {
  list[l] *= 3;
}
console.log(list);

最近は Stream API っぽい記法として、以下のように書くことも多いです。

var list = [1,2,3,4,5];
list = list.map(v => v * 3);
console.log(list);

どちらにしても、配列の要素に対して、順に決まった処理を実施していることは同じです。さて、フロー型の Node-RED では、こういった処理をどう記述したら良いのでしょうか?

まずは値ごとに分離してみる

とりあえず試してみましょう。さきほどのサンプルで、debugノードを少し右に移動し、パレットから選んだ Split ノードをその接続のうえまでドラッグして追加します。
image.png
すると接続を維持したまま Split ノードが追加されます。便利ですね。
image.png
デプロイしてinjectノードをクリックすると、配列の値がそれぞれ別に出力されることが確認できます。
image.png

次に値ごとに3倍してみる

計算をするので Function ノードですかね。さっそく Split ノードの後に追加してみましょう。
image.png

function ノードの設定を開き、名前を「* 3」に変更します。またコードの部分ですが、もともと


return msg;

となっていたコードの前に、以下のように msg.payload の値を3倍する処理を追加します。

msg.payload *= 3;
return msg;

image.png
設定後のフローはこんな感じ。
image.png
デプロイしてinjectノードをクリックすると、配列の値がそれぞれ3倍されて出力されることが確認できます。
image.png

最後はひとつの配列にまとめます

個々の値の計算はできたので、あとは配列に戻すだけですね。Split ノードと対になるノード、join ノードを function ノードの後に追加しましょう。
image.png
こんな感じで、特に設定はいりません。デプロイしてinjectノードをクリックすると、結果がちゃんと配列にまとめられているのが確認できます。
image.png
これで配列の中身を3倍するフローが完成ですね!

モヤモヤします

配列の値をそれぞれ、ちゃんと3倍できました!これでハッピーエンドとしたいのですが。駄目です、私には大きなモヤモヤが残ってしまいました。

join ノードの動きが謎です。

join ノードは、フローを流れてくる値をまとめてくれます。それは良いとして。でも単にフローの中で待っている join ノードなのに、どうして間違いなく5個まとめることができたのでしょうか?

私が超高速で injectノードを2回クリックしたとき、10個の配列ではなく、ちゃんと5個の配列を2つ返せたのは何故なのか?

debug してみよう

疑問に思ったら調べてみましょう。debug ノードを split ノードの直後に追加し、表示対象を「msg全体」に変更します。
image.png
デプロイしてinjectノードをクリックし、表示内容を確認してみましょう。以下は配列の最初の要素に対する出力です。
image.png
受け渡される msg オブジェクトに、parts というオブジェクトが追加されているのがわかります。このオブジェクトが元の配列の情報を保持していて、join ノードはこの値を参照して配列の操作をしていることが想像できます。

意地悪してみよう

join ノードが parts オブジェクトを参照しているか、ちょっと意地悪をして試してみましょう。function ノードに記載したコードで、以下のように msg.parts.count の値を変更してしまいます。

msg.payload *= 3;
msg.parts.count = 4;
return msg;

image.png
デプロイしてinjectノードをクリックし、表示内容を確認してみましょう。
image.png
出力される配列の要素数が4個に減ってしまっているのがわかります。うん、やはり parts オブジェクトを参照していましたね!

5個目の値はどうやら捨てられてしまったようです。想像ですが msg.parts.count が 4 なので、join ノードは長さが4の配列だと思い込み、4個目の値が入力されたところで配列を出力してしまったのでしょう。そこに5個目が届いても、もうそのIDは処理が終了していますし、index が0ではない値ですし、更に index が4個の上限を超えていますから、異常値と判断して出力しなかったのだと考えられます。

というわけで

split ノードで分割した場合、元の配列の情報は msg.parts オブジェクトに格納されており、join ノードではそれを参照して配列に戻しているようです。

function ノードなどに記載する自身のコードでは、msg.parts には不用意に触らないほうが良さそうですね。

おわりに

配列を操作して遊ぶだけで第二歩の投稿が終わってしまいました。

でもフロー型の記述らしいサンプルになった気がしますし、疑問がひとつ解消できたので、個人的にはちょっと満足していたりします。次は function ノードに関して です。

ではでは。

14
11
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
14
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?