Node-REDでランダムにデータを作りたいと思ってフローを書いていたら、簡単そうなことなのに、ちょっとつまずきました。
ことの顛末と解決方法について書きたいと思います。
こんな事象
やりたかったこと
aからeまでの5つの文字からランダムに文字を取得したい。
そこで、こんな感じのJSONata式を書きました。
["a", "b", "c", "d", "e"][$floor($random()*5)]
処理の意味としては、
$random()
を使用して、0以上1未満のランダムな小数を生成して、配列の長さをかけ算します。
$floor()
を使用して小数点以下を切り捨て、ランダムな整数のインデックスを得ます。
得られたインデックスを使用して、対象の配列からランダムな文字を取得します。
これでできそうと思ってフローを作り、実行してみました。
やってみたら、うまくいかない
いざ、injectノードをクリックしてみると、うまく一文字だけ出力されたり、時折、["a","d"]
といった風に2個でてきたり、Undefined になったりします。
環境は、enebularで動いているNode-RED v3.0.2-n.1です。
解決方法
FunctionノードとJSONata式の2通りの方法を試したところ、うまくいきました。
いずれもChatGPT 3.5に聞きました😅
Functionノードでの解決
FunctionノードでJavaScriptを書いて解決する方法です。いずれもChatGPTに聞いたところ、
// ランダムな文字を選択する配列
const characters = ["a", "b", "c", "d", "e"];
// ランダムなインデックスを生成
const randomIndex = Math.floor(Math.random() * characters.length);
// ランダムな文字を取得
const randomCharacter = characters[randomIndex];
// 結果を出力
msg.payload = randomCharacter;
return msg;
ちゃんとランダムな文字列が出てきました。
ですが、うまくいって当然な気もします。
JSONataでの解決
次に、改めてJSONata式でやってみます。
今度は、$random
ではなく、$shuffle
を使います。
$shuffle(["a", "b", "c","d", "e"])[0]
処理の意味としては、
$shuffle()
を使用して、配列の値の順番をごちゃまぜにします。
得られた配列の一番最初の値(0番目)を取得すれば結果的にランダムになります。
まとめ
Node-REDでフローを分かりやすく書きたいときにJSONataを重宝しています。
シャッフルなんて知らなかったですが、もっと早く気がつけばよかったです。
教えてくれたChatGPTに感謝します。JSONata式は奥が深いです。