{
  "name": "地域ごとの降水確率をまとめる",
  "nodes": [
    {
      "parameters": {
        "content": "## 何をするワークフローか\n\n毎朝7時に気象庁のAPIから複数地域の降水確率を取り、**地域ごとに最大と平均**を出して\n通知用の本文にまとめる。認証情報は使わないので、インポートしてすぐ動く。\n\n## 触るところ\n\n**「取得する地域」** の中の配列。areaCode は気象庁のエリアコード。\n\n## 通知を繋ぐには\n\n**「通知の形に整える」** の後ろに Slack / メールなどを繋ぎ、本文に `{{ $json.本文 }}` を入れる。\n\n## 注意\n\n- pops は**文字列の配列**。数値に直さずに集計すると、**エラーも出ないまま平均が null になる**\n- 1つの県が複数の細分区域を持つので、**3地域を指定しても出力は3行にならない**\n- 失敗した地域は下の「失敗を1行にまとめる」に流れる。全体は止まらない",
        "height": 480,
        "width": 620,
        "color": 4
      },
      "id": "c1000000-0000-4000-8000-000000000001",
      "name": "説明",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -60,
        -560
      ]
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "days",
              "triggerAtHour": 7,
              "triggerAtMinute": 0
            }
          ]
        }
      },
      "id": "c1000000-0000-4000-8000-000000000002",
      "name": "毎朝7時",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "language": "javaScript",
        "jsCode": "// 取りたい地域をここに並べる。areaCode は気象庁のエリアコード。\n// 1つの県が複数の細分区域を持つので、3件指定しても集計結果は3行にならない。\nreturn [\n  { json: { label: '東京', areaCode: '130000' } },\n  { json: { label: '大阪', areaCode: '270000' } },\n  { json: { label: '福岡', areaCode: '400000' } },\n];"
      },
      "id": "c1000000-0000-4000-8000-000000000003",
      "name": "取得する地域",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        220,
        0
      ]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "={{ \"https://www.jma.go.jp/bosai/forecast/data/forecast/\" + $json.areaCode + \".json\" }}",
        "authentication": "none",
        "options": {
          "timeout": 20000
        }
      },
      "id": "c1000000-0000-4000-8000-000000000004",
      "name": "予報を取得",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.5,
      "position": [
        440,
        0
      ],
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "language": "javaScript",
        "jsCode": "// 気象庁のレスポンスは2要素の配列。週間予報の方には使いたい形の pops が無いので落とす。\n// pops は「文字列の配列」なので、必ず数値に直してから Summarize に渡すこと。\n// 文字列のまま average に渡すと、エラーも出ないまま null になる。\nconst out = [];\nfor (const item of $input.all()) {\n  const series = item.json.timeSeries;\n  if (!series || !series[1] || !series[1].areas) continue;\n\n  for (const area of series[1].areas) {\n    if (!area.pops) continue;\n\n    area.pops.forEach((p, i) => {\n      // 空文字は週間予報側に混ざる。集計に入れると母数が狂うので捨てる\n      if (p === '' || p === null || p === undefined) return;\n\n      out.push({\n        json: {\n          地域: area.area.name,\n          時刻: series[1].timeDefines[i],\n          降水確率: Number(p),   // ← ここが肝。文字列のままにしない\n        },\n      });\n    });\n  }\n}\nreturn out;"
      },
      "id": "c1000000-0000-4000-8000-000000000005",
      "name": "降水確率を1件ずつにする",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        660,
        0
      ]
    },
    {
      "parameters": {
        "fieldsToSummarize": {
          "values": [
            {
              "aggregation": "max",
              "field": "降水確率"
            },
            {
              "aggregation": "average",
              "field": "降水確率"
            },
            {
              "aggregation": "count",
              "field": "降水確率"
            }
          ]
        },
        "fieldsToSplitBy": "地域",
        "options": {}
      },
      "id": "c1000000-0000-4000-8000-000000000006",
      "name": "地域ごとに集計",
      "type": "n8n-nodes-base.summarize",
      "typeVersion": 1.1,
      "position": [
        880,
        0
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "language": "javaScript",
        "jsCode": "// 降水確率が高い順に並べて、そのまま送れる本文をつくる\nconst rows = $input.all().map(i => i.json)\n  .sort((a, b) => b.max_降水確率 - a.max_降水確率);\n\nconst 本文 = ['【今日の降水確率】']\n  .concat(rows.map(r =>\n    r.地域 + ': 最大 ' + r.max_降水確率 + '% / 平均 ' + Math.round(r.average_降水確率) + '%'\n  ))\n  .join('\\n');\n\nreturn [{ json: { 件数: rows.length, 本文, 明細: rows } }];"
      },
      "id": "c1000000-0000-4000-8000-000000000007",
      "name": "通知の形に整える",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1100,
        0
      ]
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "language": "javaScript",
        "jsCode": "// エラー出力には、元の入力（label / areaCode）が残ったまま届く。\n// だからどの地域で失敗したのかが分かる。\nreturn $input.all().map(item => ({\n  json: {\n    label: item.json.label,\n    areaCode: item.json.areaCode,\n    httpCode: item.json.details ? item.json.details.httpCode : null,\n    message: item.json.details ? item.json.details.message : String(item.json.error),\n    failedAt: new Date().toISOString(),\n  },\n}));"
      },
      "id": "c1000000-0000-4000-8000-000000000008",
      "name": "失敗を1行にまとめる",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        660,
        220
      ]
    }
  ],
  "connections": {
    "毎朝7時": {
      "main": [
        [
          {
            "node": "取得する地域",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "取得する地域": {
      "main": [
        [
          {
            "node": "予報を取得",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "予報を取得": {
      "main": [
        [
          {
            "node": "降水確率を1件ずつにする",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "失敗を1行にまとめる",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "降水確率を1件ずつにする": {
      "main": [
        [
          {
            "node": "地域ごとに集計",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "地域ごとに集計": {
      "main": [
        [
          {
            "node": "通知の形に整える",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "pinData": {}
}
