✂️ Node-RED Splitノード ガイド

このガイドでは、Node-REDのSplitノードについて、初心者の方でも理解できるように詳しく説明します。

📚 1. Splitノードとは?

🤔 「Split」って何?

Splitノードは、1つのメッセージを複数のメッセージに分割するノードです。 日常生活で例えると、ピザを切り分けるようなものです。

🍕 ピザの切り分けに例えると:

📦 基本的な動作

Inject Split →→→ Debug

Splitノードは、配列、文字列、オブジェクトなどを受け取り、それぞれの要素を個別のメッセージとして順次送信します。 後でJoinノードと組み合わせて、分割したメッセージを再結合することもできます。

入力(1メッセージ)
["Apple", "Orange", "Banana"]
↓ Split ↓
出力(3メッセージ)
"Apple" → "Orange" → "Banana"

⚙️ 2. Splitノードの設定

🔧 入力データ別の動作

文字列 String

指定した区切り文字で分割

"Apple,Orange,Banana" ↓ カンマで分割 "Apple" → "Orange" → "Banana"

配列 Array

各要素を個別メッセージに

["A", "B", "C"] ↓ 分割 "A" → "B" → "C"

オブジェクト Object

各プロパティをキー/値ペアに

{a: 1, b: 2} ↓ 分割 {payload: 1, topic: "a"} {payload: 2, topic: "b"}

バッファ Buffer

固定長または区切りバイトで分割

Buffer(12バイト) ↓ 4バイトごと Buffer(4) → Buffer(4) → Buffer(4)

📋 設定項目

設定項目 説明
に基づく 分割対象のメッセージプロパティ msg.payload
分割 文字列の場合の区切り文字 \n(改行), ,(カンマ), 任意の文字
固定長 指定した文字数/バイト数で分割 4文字ごと、100バイトごと
分割 配列を指定個数ずつに分割 2個ずつ、10個ずつ
keyのコピー先 オブジェクト分割時のキー格納先 msg.topic, msg.key
メッセージのストリームとして処理 メッセージの区切りをまたいで分割 大きなファイルの処理

🎯 msg.partsオブジェクト

Splitノードは分割情報をmsg.partsに自動的に追加します。これはJoinノードで再結合する際に使用されます。

msg.parts = { id: "abc123", // 分割グループの識別子 index: 0, // このメッセージの順番(0から) count: 3, // 総分割数 type: "array", // 元のデータ型 key: "Apple" // オブジェクト分割時のキー名 }

🎯 3. 実用的な使用パターン

📥 サンプルフローのインポート方法:

  1. 下のサンプルフローJSONをコピー
  2. Node-REDエディタで メニュー → 読み込み を選択
  3. JSONをペーストして「読み込み」をクリック

このサンプルフローには、以下で説明する全パターンの実例が含まれています。

📋 サンプルフロー(クリックで展開)

参照元:NodeREDエディター内サンプルフロー

[ { "id": "0276807ceed12df2", "type": "tab", "label": "split", "disabled": false, "info": "", "env": [] }, { "id": "f94ffc33.76f83", "type": "comment", "z": "0276807ceed12df2", "name": "Example: Split Message Payload", "info": "Split node can be used to split message payload into multiple messages.", "x": 330, "y": 120, "wires": [] }, { "id": "657bb57c.a3f98c", "type": "split", "z": "0276807ceed12df2", "name": "", "splt": "\\n", "spltType": "str", "arraySplt": 1, "arraySpltType": "len", "stream": false, "addname": "", "property": "payload", "x": 650, "y": 220, "wires": [ [ "14228ff.ae24f7" ] ] }, { "id": "2afece55.b87de2", "type": "inject", "z": "0276807ceed12df2", "name": "", "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 360, "y": 220, "wires": [ [ "cfca3863.d961d8" ] ] }, { "id": "cfca3863.d961d8", "type": "template", "z": "0276807ceed12df2", "name": "data", "field": "payload", "fieldType": "msg", "format": "handlebars", "syntax": "plain", "template": "Apple\nOrange\nBanana", "output": "str", "x": 510, "y": 220, "wires": [ [ "657bb57c.a3f98c" ] ] }, { "id": "14228ff.ae24f7", "type": "debug", "z": "0276807ceed12df2", "name": "", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "x": 800, "y": 220, "wires": [] }, { "id": "9a3c9494.b5d178", "type": "comment", "z": "0276807ceed12df2", "name": "Split input text by specified string", "info": "", "x": 370, "y": 180, "wires": [] }, { "id": "38c873c.5ae718c", "type": "comment", "z": "0276807ceed12df2", "name": "→ split by newline (\\n)", "info": "", "x": 700, "y": 260, "wires": [] }, { "id": "bdfa12b9.3fbbc", "type": "split", "z": "0276807ceed12df2", "name": "", "splt": "4", "spltType": "len", "arraySplt": 1, "arraySpltType": "len", "stream": false, "addname": "", "property": "payload", "x": 650, "y": 340, "wires": [ [ "debf23bb.c0245" ] ] }, { "id": "7c0948db.e35d38", "type": "inject", "z": "0276807ceed12df2", "name": "", "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 360, "y": 340, "wires": [ [ "7f791b7d.94cad4" ] ] }, { "id": "7f791b7d.94cad4", "type": "template", "z": "0276807ceed12df2", "name": "data", "field": "payload", "fieldType": "msg", "format": "handlebars", "syntax": "plain", "template": "Apple\nOrange\nBanana", "output": "str", "x": 510, "y": 340, "wires": [ [ "bdfa12b9.3fbbc" ] ] }, { "id": "debf23bb.c0245", "type": "debug", "z": "0276807ceed12df2", "name": "", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "x": 800, "y": 340, "wires": [] }, { "id": "f05e98a3.4182c8", "type": "comment", "z": "0276807ceed12df2", "name": "Split input text by specified number of characters", "info": "", "x": 420, "y": 300, "wires": [] }, { "id": "86b52b51.2258d8", "type": "comment", "z": "0276807ceed12df2", "name": "→ split by four characters", "info": "", "x": 710, "y": 380, "wires": [] }, { "id": "71d7c0e0.c0316", "type": "split", "z": "0276807ceed12df2", "name": "", "splt": "\\n", "spltType": "str", "arraySplt": 1, "arraySpltType": "len", "stream": false, "addname": "", "property": "payload", "x": 650, "y": 480, "wires": [ [ "bee5b6a2.a955a8" ] ] }, { "id": "1cdc2df9.bebdd2", "type": "inject", "z": "0276807ceed12df2", "name": "", "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 360, "y": 480, "wires": [ [ "f30df13c.19475" ] ] }, { "id": "f30df13c.19475", "type": "template", "z": "0276807ceed12df2", "name": "data", "field": "payload", "fieldType": "msg", "format": "json", "syntax": "plain", "template": "[ \n \"Apple\",\n \"Orange\",\n \"Banana\"\n]", "output": "json", "x": 510, "y": 480, "wires": [ [ "71d7c0e0.c0316" ] ] }, { "id": "bee5b6a2.a955a8", "type": "debug", "z": "0276807ceed12df2", "name": "", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "x": 800, "y": 480, "wires": [] }, { "id": "b2c731fe.abda4", "type": "comment", "z": "0276807ceed12df2", "name": "Split input array", "info": "", "x": 320, "y": 440, "wires": [] }, { "id": "1f557227.d0910e", "type": "comment", "z": "0276807ceed12df2", "name": "→ split array", "info": "", "x": 670, "y": 520, "wires": [] }, { "id": "c0d43ff4.291d8", "type": "split", "z": "0276807ceed12df2", "name": "", "splt": "\\n", "spltType": "str", "arraySplt": 1, "arraySpltType": "len", "stream": false, "addname": "topic", "property": "payload", "x": 650, "y": 600, "wires": [ [ "fc9fe458.50fd18" ] ] }, { "id": "6d52ce8a.0c715", "type": "inject", "z": "0276807ceed12df2", "name": "", "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 360, "y": 600, "wires": [ [ "bdeb8c21.1c6b7" ] ] }, { "id": "bdeb8c21.1c6b7", "type": "template", "z": "0276807ceed12df2", "name": "data", "field": "payload", "fieldType": "msg", "format": "json", "syntax": "plain", "template": "{ \n \"Apple\": 80,\n \"Orange\": 100,\n \"Banana\": 50\n}", "output": "json", "x": 510, "y": 600, "wires": [ [ "c0d43ff4.291d8" ] ] }, { "id": "fc9fe458.50fd18", "type": "debug", "z": "0276807ceed12df2", "name": "", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "true", "targetType": "full", "x": 780, "y": 600, "wires": [] }, { "id": "48956e14.79b86", "type": "comment", "z": "0276807ceed12df2", "name": "Split object to key/value pairs", "info": "", "x": 360, "y": 560, "wires": [] }, { "id": "d528c2c2.6efc7", "type": "comment", "z": "0276807ceed12df2", "name": "→ split object", "info": "", "x": 670, "y": 640, "wires": [] } ]

パターン1: 文字列を区切り文字で分割

用途: テキストデータを行ごと、カンマ区切りなどで分割

Inject Template
(テキスト生成)
Split
(\n)
→→→ Debug

📌 動作の流れ:

  1. "Apple\nOrange\nBanana" を受信
  2. 改行文字(\n)で分割
  3. "Apple" → "Orange" → "Banana" を順次送信

設定例:

分割: 文字列 "\n" 入力: "Apple\nOrange\nBanana" 出力: 3つのメッセージ 1. msg.payload = "Apple" 2. msg.payload = "Orange" 3. msg.payload = "Banana"

パターン2: 文字列を固定長で分割

用途: 固定長レコードのデータを処理

Inject Template Split
(4文字)
→→→ Debug

📌 動作の流れ:

  1. "Apple\nOrange\nBanana" (19文字)を受信
  2. 4文字ずつ分割
  3. "Appl" → "e\nOr" → "ange" → "\nBan" → "ana" を順次送信

設定例:

分割: 固定長 4文字 入力: "AAAABBBBCCCC" 出力: 3つのメッセージ 1. msg.payload = "AAAA" 2. msg.payload = "BBBB" 3. msg.payload = "CCCC"

パターン3: 配列を要素ごとに分割

用途: 配列の各要素を個別に処理

Inject Template
(JSON配列)
Split →→→ Debug

📌 動作の流れ:

  1. ["Apple", "Orange", "Banana"] を受信
  2. 配列を自動認識して分割
  3. "Apple" → "Orange" → "Banana" を順次送信

設定例:

分割: 配列 (自動認識) 入力: ["Apple", "Orange", "Banana"] 出力: 3つのメッセージ 1. msg.payload = "Apple", msg.parts.index = 0 2. msg.payload = "Orange", msg.parts.index = 1 3. msg.payload = "Banana", msg.parts.index = 2

パターン4: オブジェクトをキー/値ペアに分割

用途: オブジェクトの各プロパティを個別に処理

Inject Template
(JSONオブジェクト)
Split
(topic=key)
→→→ Debug

📌 動作の流れ:

  1. {Apple: 80, Orange: 100, Banana: 50} を受信
  2. オブジェクトを自動認識して分割
  3. 各プロパティを個別メッセージとして送信
  4. キー名は msg.topic に格納

設定例:

分割: オブジェクト キー追加先: msg.topic 入力: {"Apple": 80, "Orange": 100, "Banana": 50} 出力: 3つのメッセージ 1. msg.payload = 80, msg.topic = "Apple" 2. msg.payload = 100, msg.topic = "Orange" 3. msg.payload = 50, msg.topic = "Banana"

パターン5: Split + Joinの組み合わせ

用途: 配列の各要素を加工して再結合

Inject Split Function
(加工)
Join Debug

📌 動作の流れ:

  1. [1, 2, 3] を受信してSplitで分割
  2. Functionで各値を2倍に加工
  3. Joinで再結合して [2, 4, 6] を出力

※ msg.partsが保持されているので、Joinノードで自動的に再結合できます

🏋️ 4. 実践演習

演習1: CSVデータの分割初級

📝 課題:

カンマ区切りのテキストを個別のメッセージに分割してください。

🎯 要求仕様:

📊 期待される動作:

✅ 成功の条件:

💡 ヒント

Splitノードの設定:

  • 分割方法: 文字列
  • 区切り文字: , (カンマ)

Injectノードの設定:

  • payload: 文字列型で "東京,大阪,名古屋,福岡"
✅ 解答例フロー
[ { "id": "ex1_inject", "type": "inject", "name": "CSV入力", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "東京,大阪,名古屋,福岡", "payloadType": "str", "x": 120, "y": 100, "wires": [["ex1_split"]] }, { "id": "ex1_split", "type": "split", "name": "カンマ分割", "splt": ",", "spltType": "str", "arraySplt": 1, "arraySpltType": "len", "stream": false, "addname": "", "property": "payload", "x": 290, "y": 100, "wires": [["ex1_debug"]] }, { "id": "ex1_debug", "type": "debug", "name": "結果", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "x": 450, "y": 100, "wires": [] } ]

演習2: 配列の分割と加工中級

📝 課題:

数値の配列を分割し、各値を2倍にして出力してください。

🎯 要求仕様:

📊 期待される動作:

✅ 成功の条件:

💡 ヒント

Injectノードの設定:

  • payload: JSON型で [10, 20, 30, 40, 50]

Splitノード:

  • 配列は自動認識されるのでデフォルト設定でOK

Functionノード:

  • msg.payload = msg.payload * 2;
✅ 解答例フロー
[ { "id": "ex2_inject", "type": "inject", "name": "数値配列", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "[10,20,30,40,50]", "payloadType": "json", "x": 120, "y": 100, "wires": [["ex2_split"]] }, { "id": "ex2_split", "type": "split", "name": "分割", "splt": "\\n", "spltType": "str", "arraySplt": 1, "arraySpltType": "len", "stream": false, "addname": "", "property": "payload", "x": 270, "y": 100, "wires": [["ex2_function"]] }, { "id": "ex2_function", "type": "function", "name": "2倍にする", "func": "// 値を2倍にする\n\nmsg.payload = msg.payload * 2;\n\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "x": 420, "y": 100, "wires": [["ex2_debug"]] }, { "id": "ex2_debug", "type": "debug", "name": "結果", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "x": 570, "y": 100, "wires": [] } ]

演習3: オブジェクトの分割と集計中級

📝 課題:

商品と価格のオブジェクトを分割し、各商品の情報を整形して出力してください。

🎯 要求仕様:

📊 期待される動作:

✅ 成功の条件:

💡 ヒント

Splitノードの設定:

  • キー追加先: msg.topic

Changeノード(JSONata式):

  • msg.topicにキー名(商品名)が入る
  • msg.payloadに値(価格)が入る
  • JSONata式でこれらを組み合わせて文字列を作成
  • topic & ": " & $string(payload) & "円"
✅ 解答例フロー
[ { "id": "ex3_inject", "type": "inject", "name": "商品データ", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "{\"りんご\":150,\"みかん\":80,\"バナナ\":120}", "payloadType": "json", "x": 130, "y": 100, "wires": [["ex3_split"]] }, { "id": "ex3_split", "type": "split", "name": "分割", "splt": "\\n", "spltType": "str", "arraySplt": 1, "arraySpltType": "len", "stream": false, "addname": "topic", "property": "payload", "x": 290, "y": 100, "wires": [["ex3_change"]] }, { "id": "ex3_change", "type": "change", "name": "整形", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "topic & \": \" & $string(payload) & \"円\"", "tot": "jsonata" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 430, "y": 100, "wires": [["ex3_debug"]] }, { "id": "ex3_debug", "type": "debug", "name": "結果", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "x": 570, "y": 100, "wires": [] } ]

演習4: Split + Joinで配列を加工上級

📝 課題:

文字列の配列を分割し、各文字列を大文字に変換して、再度配列に結合してください。

🎯 要求仕様:

📊 期待される動作:

✅ 成功の条件:

💡 ヒント

Changeノード(JSONata式):

  • msg.payloadに $uppercase(payload) をセット

Joinノード:

  • モード: 自動 (msg.partsを使用)
  • Splitが付与したmsg.partsを使って自動結合
✅ 解答例フロー
[ { "id": "ex4_inject", "type": "inject", "name": "文字列配列", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "[\"apple\",\"orange\",\"banana\"]", "payloadType": "json", "x": 130, "y": 100, "wires": [["ex4_split"]] }, { "id": "ex4_split", "type": "split", "name": "分割", "splt": "\\n", "spltType": "str", "arraySplt": 1, "arraySpltType": "len", "stream": false, "addname": "", "property": "payload", "x": 270, "y": 100, "wires": [["ex4_change"]] }, { "id": "ex4_change", "type": "change", "name": "大文字変換", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "$uppercase(payload)", "tot": "jsonata" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 410, "y": 100, "wires": [["ex4_join"]] }, { "id": "ex4_join", "type": "join", "name": "結合", "mode": "auto", "build": "array", "property": "payload", "propertyType": "msg", "key": "topic", "joiner": "\\n", "joinerType": "str", "accumulate": "false", "timeout": "", "count": "", "reduceRight": false, "reduceExp": "", "reduceInit": "", "reduceInitType": "", "reduceFixup": "", "x": 550, "y": 100, "wires": [["ex4_debug"]] }, { "id": "ex4_debug", "type": "debug", "name": "結果", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "x": 690, "y": 100, "wires": [] } ]

🎓 5. まとめ

Splitノードの重要ポイント

⚠️ よくある間違い

📚 次のステップ

Splitノードをマスターしたら、以下のノードも学んでみましょう:

🔧 6. トラブルシューティング

よくある問題と解決方法

問題 原因 解決方法
分割されない 区切り文字が存在しない 入力データと区切り文字を確認
1文字ずつ分割される 配列ではなく文字列として処理 JSONノードで配列に変換してから分割
Joinで結合できない msg.partsが削除されている 途中の処理でmsg.partsを保持
順序がバラバラ 非同期処理による順序変更 msg.parts.indexで並べ替え
メモリ不足 巨大な配列を一度に分割 ストリームモードを使用

💡 7. 実務での活用例

ケース1: ログファイルの行ごと処理

ログファイル読み込み ↓ Split(改行で分割) ↓ 各行を解析・フィルタリング ↓ アラート or DB保存

ケース2: センサーデータのバッチ処理

複数センサーからのデータ配列 ↓ Split(配列を分割) ↓ 各センサーデータを個別処理 ↓ 閾値チェック・アラート発報

ケース3: APIレスポンスの個別処理

API: ユーザー一覧取得 ↓ Split(配列を分割) ↓ 各ユーザーにメール送信 ↓ Join(結果を集約)

ケース4: 設定ファイルの解析

JSON設定ファイル(オブジェクト) ↓ Split(キー/値に分割) ↓ 各設定を個別に検証 ↓ エラーがあれば通知

📗 8. 追加リソース


このガイドが役に立ちましたら、実際のプロジェクトで練習してみてください!
Splitノードはデータ処理の強力なツールです。

参照元:NodeREDエディター内サンプルフロー

🏠