🔢 Node-RED Sortノード ガイド

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

📚 1. Sortノードとは?

🤔 「Sort」って何?

Sortノードは、配列やメッセージシーケンスを並べ替えるノードです。 日常生活で例えると、図書館の司書が本を著者名順やタイトル順に棚に並べ替えるような作業です。

📚 図書館の本の整理に例えると:

📦 基本的な動作

Inject Template Sort Debug

Sortノードは、配列またはメッセージシーケンスを受け取り、指定した条件で並べ替えて出力します。 文字列順、数値順、オブジェクトのプロパティ順など、様々な方法でソートできます。

入力(未ソート)
["orange", "banana", "apple", "kiwi"]
↓ Sort(昇順) ↓
出力(ソート済み)
["apple", "banana", "kiwi", "orange"]

⚙️ 2. Sortノードの2つのモード

配列 配列ソート

msg.payloadの配列を並べ替え

配列の要素を 直接ソート

シーケンス メッセージシーケンス

Splitで分割したメッセージを並べ替え

msg.partsを使用して メッセージ順序を変更

📋 設定項目一覧

設定項目 説明 選択肢
ソート対象 配列またはメッセージシーケンスを選択 msg.payload / メッセージシーケンス
ソート順 昇順または降順を選択 昇順 / 降順
数値として 数値としてソートするかどうか チェックボックス
キー ソートの基準となる値を指定 要素の値 / JSONata式

🎯 文字列ソート vs 数値ソート

同じデータでも「文字列として」と「数値として」でソート結果が異なります。

入力
["1024", "86", "256", "100", "9"]
↓ ソート ↓
文字列順
["100", "1024", "256", "86", "9"]

数値順
["9", "86", "100", "256", "1024"]

📌 文字列順と数値順の違い:

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

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

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

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

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

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

[ { "id": "9b4586fe59798b63", "type": "tab", "label": "sort", "disabled": false, "info": "", "env": [] }, { "id": "6451c8bb.b52278", "type": "sort", "z": "9b4586fe59798b63", "name": "", "order": "ascending", "as_num": false, "target": "payload", "targetType": "msg", "msgKey": "", "msgKeyType": "elem", "seqKey": "payload", "seqKeyType": "msg", "x": 570, "y": 200, "wires": [["cb34307c.ac1dd"]] }, { "id": "638546c.38f1fb8", "type": "inject", "z": "9b4586fe59798b63", "name": "", "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 280, "y": 200, "wires": [["db5d90ac.bbb3f"]] }, { "id": "3ec02cae.012ce4", "type": "comment", "z": "9b4586fe59798b63", "name": "Sort array payload as string in ascending order", "info": "", "x": 340, "y": 140, "wires": [] }, { "id": "db5d90ac.bbb3f", "type": "template", "z": "9b4586fe59798b63", "name": "data", "field": "payload", "fieldType": "msg", "format": "json", "syntax": "mustache", "template": "[\"orange\", \"banana\", \"apple\", \"pear\", \"kiwi\"]", "output": "json", "x": 430, "y": 200, "wires": [["6451c8bb.b52278"]] }, { "id": "cb34307c.ac1dd", "type": "debug", "z": "9b4586fe59798b63", "name": "", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "x": 730, "y": 200, "wires": [] }, { "id": "735ec14e.4ed55", "type": "sort", "z": "9b4586fe59798b63", "name": "", "order": "descending", "as_num": false, "target": "payload", "targetType": "msg", "msgKey": "", "msgKeyType": "elem", "seqKey": "payload", "seqKeyType": "msg", "x": 570, "y": 360, "wires": [["e8dc4ae5.f08598"]] }, { "id": "c8ce4e74.9db68", "type": "inject", "z": "9b4586fe59798b63", "name": "", "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 280, "y": 360, "wires": [["ea0384a6.1346b8"]] }, { "id": "70333397.d78f6c", "type": "comment", "z": "9b4586fe59798b63", "name": "Sort array payload as string in descending order", "info": "", "x": 340, "y": 300, "wires": [] }, { "id": "ea0384a6.1346b8", "type": "template", "z": "9b4586fe59798b63", "name": "data", "field": "payload", "fieldType": "msg", "format": "json", "syntax": "mustache", "template": "[\"orange\", \"banana\", \"apple\", \"pear\", \"kiwi\"]", "output": "json", "x": 430, "y": 360, "wires": [["735ec14e.4ed55"]] }, { "id": "e8dc4ae5.f08598", "type": "debug", "z": "9b4586fe59798b63", "name": "", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "x": 730, "y": 360, "wires": [] }, { "id": "d4b49c22.32685", "type": "sort", "z": "9b4586fe59798b63", "name": "", "order": "ascending", "as_num": true, "target": "payload", "targetType": "msg", "msgKey": "", "msgKeyType": "elem", "seqKey": "payload", "seqKeyType": "msg", "x": 570, "y": 520, "wires": [["45738f07.16416"]] }, { "id": "87ce9955.924868", "type": "inject", "z": "9b4586fe59798b63", "name": "", "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 280, "y": 520, "wires": [["30b81283.f0772e"]] }, { "id": "f6e624df.703a88", "type": "comment", "z": "9b4586fe59798b63", "name": "Sort array payload as number", "info": "", "x": 280, "y": 460, "wires": [] }, { "id": "30b81283.f0772e", "type": "template", "z": "9b4586fe59798b63", "name": "data", "field": "payload", "fieldType": "msg", "format": "json", "syntax": "mustache", "template": "[\"1024\", \"86\", \"256\", \"100\", \"9\"]", "output": "json", "x": 430, "y": 520, "wires": [["d4b49c22.32685"]] }, { "id": "45738f07.16416", "type": "debug", "z": "9b4586fe59798b63", "name": "", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "x": 730, "y": 520, "wires": [] }, { "id": "b91c19b1.b66b18", "type": "sort", "z": "9b4586fe59798b63", "name": "", "order": "ascending", "as_num": false, "target": "payload", "targetType": "msg", "msgKey": "price", "msgKeyType": "jsonata", "seqKey": "payload", "seqKeyType": "msg", "x": 570, "y": 680, "wires": [["32dd80a1.226e4"]] }, { "id": "adb0daa2.d85a48", "type": "inject", "z": "9b4586fe59798b63", "name": "", "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 280, "y": 680, "wires": [["b3ee1b9e.dbf388"]] }, { "id": "d1190f8b.9a74b", "type": "comment", "z": "9b4586fe59798b63", "name": "Sort array of objects using JSONata (price)", "info": "", "x": 340, "y": 620, "wires": [] }, { "id": "b3ee1b9e.dbf388", "type": "template", "z": "9b4586fe59798b63", "name": "data", "field": "payload", "fieldType": "msg", "format": "json", "syntax": "mustache", "template": "[{\"name\": \"orange\", \"price\": 80}, {\"name\": \"banana\", \"price\": 250}, {\"name\": \"apple\", \"price\": 100}]", "output": "json", "x": 430, "y": 680, "wires": [["b91c19b1.b66b18"]] }, { "id": "32dd80a1.226e4", "type": "debug", "z": "9b4586fe59798b63", "name": "", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "x": 730, "y": 680, "wires": [] } ]

パターン1: 配列の昇順ソート(文字列)

用途: 文字列配列をアルファベット順に並べ替え

Inject Template Sort
(昇順)
Debug

📌 動作の流れ:

  1. ["orange", "banana", "apple", "kiwi"] を入力
  2. Sortノードが文字列として昇順ソート
  3. ["apple", "banana", "kiwi", "orange"] を出力

設定例:

ソート対象: msg.payload ソート順: 昇順 数値として: OFF 入力: ["orange", "banana", "apple", "kiwi"] 出力: ["apple", "banana", "kiwi", "orange"]

パターン2: 配列の降順ソート

用途: 配列を逆順に並べ替え

Inject Template Sort
(降順)
Debug

設定例:

ソート対象: msg.payload ソート順: 降順 数値として: OFF 入力: ["orange", "banana", "apple", "kiwi"] 出力: ["pear", "orange", "kiwi", "banana", "apple"]

パターン3: 数値としてソート

用途: 数値を含む配列を数値順に並べ替え

Inject Template Sort
(数値)
Debug

📌 数値ソートのポイント:

設定例:

ソート対象: msg.payload ソート順: 昇順 数値として: ON 入力: ["1024", "86", "256", "100", "9"] 出力: ["9", "86", "100", "256", "1024"]

パターン4: オブジェクト配列のソート(JSONata式)

用途: オブジェクトの特定プロパティで並べ替え

Inject Template
(商品配列)
Sort
(price)
Debug

📌 JSONata式でのソート:

設定例:

ソート対象: msg.payload キー: price (JSONata式) ソート順: 昇順 入力: [ {"name": "orange", "price": 80}, {"name": "banana", "price": 250}, {"name": "apple", "price": 100} ] 出力: [ {"name": "orange", "price": 80}, {"name": "apple", "price": 100}, {"name": "banana", "price": 250} ]

パターン5: 複合キーでのソート

用途: 複数の条件で並べ替え(第1キー、第2キー)

Inject Template Sort
(price+name)
Debug

設定例:

ソート対象: msg.payload キー: $substring("0000" & $string(price), -4) & name ソート順: 昇順 この式の意味: 1. priceを4桁のゼロ埋め文字列に変換(100 → "0100") 2. nameを連結("0100apple") 3. この連結文字列でソート 結果: 価格順、同じ価格なら名前順

パターン6: メッセージシーケンスのソート

用途: Splitで分割したメッセージを並べ替え

Inject Template Split →→→ Sort
(シーケンス)
→→→ Debug

📌 メッセージシーケンスのポイント:

設定例:

ソート対象: メッセージシーケンス キー: msg.payload ソート順: 昇順 入力シーケンス: "orange" → "banana" → "apple" → "kiwi" 出力シーケンス: "apple" → "banana" → "kiwi" → "orange"

🏋️ 4. 実践演習

演習1: 果物名のソート初級

📝 課題:

果物名の配列を降順(Z→A)に並べ替えてください。

🎯 要求仕様:

📊 期待される動作:

✅ 成功の条件:

💡 ヒント

Injectノードの設定:

  • payload: タイムスタンプ(デフォルト)

Templateノードの設定:

  • 形式: JSON
  • テンプレート: ["grape", "apple", "cherry", "banana"]
  • 出力: JSONオブジェクト

Sortノードの設定:

  • ソート対象: msg.payload
  • ソート順: 降順
  • 数値として: OFF(チェックなし)
✅ 解答例フロー
[ { "id": "ex1_inject", "type": "inject", "name": "実行", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 110, "y": 100, "wires": [["ex1_template"]] }, { "id": "ex1_template", "type": "template", "name": "果物配列", "field": "payload", "fieldType": "msg", "format": "json", "syntax": "plain", "template": "[\"grape\", \"apple\", \"cherry\", \"banana\"]", "output": "json", "x": 260, "y": 100, "wires": [["ex1_sort"]] }, { "id": "ex1_sort", "type": "sort", "name": "降順ソート", "order": "descending", "as_num": false, "target": "payload", "targetType": "msg", "msgKey": "", "msgKeyType": "elem", "seqKey": "payload", "seqKeyType": "msg", "x": 420, "y": 100, "wires": [["ex1_debug"]] }, { "id": "ex1_debug", "type": "debug", "name": "結果", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "x": 570, "y": 100, "wires": [] } ]

演習2: センサー値の数値ソート中級

📝 課題:

センサーから取得した数値データを昇順に並べ替えてください。

🎯 要求仕様:

📊 期待される動作:

✅ 成功の条件:

💡 ヒント

Templateノードの設定:

  • 形式: JSON
  • テンプレート: [42, 7, 128, 15, 99]
  • 出力: JSONオブジェクト

Sortノードの設定:

  • ソート対象: msg.payload
  • ソート順: 昇順
  • 数値として: ON(チェック)
✅ 解答例フロー
[ { "id": "ex2_inject", "type": "inject", "name": "実行", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 110, "y": 100, "wires": [["ex2_template"]] }, { "id": "ex2_template", "type": "template", "name": "センサー値", "field": "payload", "fieldType": "msg", "format": "json", "syntax": "plain", "template": "[42, 7, 128, 15, 99]", "output": "json", "x": 270, "y": 100, "wires": [["ex2_sort"]] }, { "id": "ex2_sort", "type": "sort", "name": "数値昇順", "order": "ascending", "as_num": true, "target": "payload", "targetType": "msg", "msgKey": "", "msgKeyType": "elem", "seqKey": "payload", "seqKeyType": "msg", "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: 商品価格でソート中級

📝 課題:

商品オブジェクトの配列を価格の安い順に並べ替えてください。

🎯 要求仕様:

📊 期待される動作:

✅ 成功の条件:

💡 ヒント

Templateノードの設定:

  • 形式: JSON
  • テンプレート例: [{"name": "Pen", "price": 150}, {"name": "Eraser", "price": 50}, {"name": "Notebook", "price": 300}]

Sortノードの設定:

  • ソート対象: msg.payload
  • キー: price(JSONata式を選択)
  • ソート順: 昇順
✅ 解答例フロー
[ { "id": "ex3_inject", "type": "inject", "name": "実行", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 110, "y": 100, "wires": [["ex3_template"]] }, { "id": "ex3_template", "type": "template", "name": "商品データ", "field": "payload", "fieldType": "msg", "format": "json", "syntax": "plain", "template": "[{\"name\": \"Pen\", \"price\": 150}, {\"name\": \"Eraser\", \"price\": 50}, {\"name\": \"Notebook\", \"price\": 300}]", "output": "json", "x": 270, "y": 100, "wires": [["ex3_sort"]] }, { "id": "ex3_sort", "type": "sort", "name": "価格順ソート", "order": "ascending", "as_num": false, "target": "payload", "targetType": "msg", "msgKey": "price", "msgKeyType": "jsonata", "seqKey": "payload", "seqKeyType": "msg", "x": 440, "y": 100, "wires": [["ex3_debug"]] }, { "id": "ex3_debug", "type": "debug", "name": "結果", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "x": 590, "y": 100, "wires": [] } ]

演習4: メッセージシーケンスのソート上級

📝 課題:

Splitで分割したメッセージシーケンスをソートし、Joinで再結合してください。

🎯 要求仕様:

📊 期待される動作:

✅ 成功の条件:

💡 ヒント

Templateノードの設定:

  • 形式: テキスト
  • テンプレート: Tokyo, Osaka, Kyoto, Nagoyaを改行で区切って入力
  • 出力: 文字列

Splitノードの設定:

  • 分割: 改行(\n)

Sortノードの設定:

  • ソート対象: メッセージシーケンス
  • キー: msg.payload
  • ソート順: 昇順

Joinノードの設定:

  • モード: 自動(または配列形式)
✅ 解答例フロー
[ { "id": "ex4_inject", "type": "inject", "name": "実行", "props": [{"p": "payload"}], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 90, "y": 100, "wires": [["ex4_template"]] }, { "id": "ex4_template", "type": "template", "name": "都市リスト", "field": "payload", "fieldType": "msg", "format": "text", "syntax": "plain", "template": "Tokyo\nOsaka\nKyoto\nNagoya", "output": "str", "x": 220, "y": 100, "wires": [["ex4_split"]] }, { "id": "ex4_split", "type": "split", "name": "分割", "splt": "\\n", "spltType": "str", "arraySplt": 1, "arraySpltType": "len", "stream": false, "addname": "", "x": 350, "y": 100, "wires": [["ex4_sort"]] }, { "id": "ex4_sort", "type": "sort", "name": "ソート", "order": "ascending", "as_num": false, "target": "payload", "targetType": "seq", "msgKey": "", "msgKeyType": "elem", "seqKey": "payload", "seqKeyType": "msg", "x": 470, "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, "x": 590, "y": 100, "wires": [["ex4_debug"]] }, { "id": "ex4_debug", "type": "debug", "name": "結果", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "x": 710, "y": 100, "wires": [] } ]

🎓 5. まとめ

Sortノードの重要ポイント

⚠️ よくある間違い

📚 次のステップ

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

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

よくある問題と解決方法

問題 原因 解決方法
ソートされない 配列でない値が入力されている 入力データが配列であることを確認
数値順にならない 「数値として」がOFF 「数値として」をONに設定
シーケンスソートが動かない msg.partsがない Splitノードを経由させる
JSONata式でエラー プロパティ名のスペルミス オブジェクトのプロパティ名を確認
結果が配列でなくバラバラ シーケンスモードで使用 Joinノードで再結合する
順序が安定しない 同じ値の要素の順序 複合キーで第2ソート条件を追加

💡 7. 実務での活用例

ケース1: IoTセンサーデータのランキング

複数センサーから温度データ受信 ↓ Sortノード(数値降順) ↓ 最も高温のセンサーが先頭 ↓ アラート判定・通知

ケース2: APIレスポンスの整理

REST APIから商品一覧取得 ↓ Sortノード(価格昇順、JSONata: price) ↓ 安い順に並び替え ↓ フロントエンドに返却

ケース3: ログデータの時系列整理

複数ソースからログ収集 ↓ Sortノード(timestamp昇順) ↓ 時系列順に整列 ↓ データベース保存

ケース4: 在庫管理の優先順位付け

倉庫の在庫データ ↓ Sortノード(数量昇順) ↓ 在庫が少ない順にソート ↓ 発注アラート生成

🔗 8. 追加リソース


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

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

🏠