kun432's blog

Alexaなどスマートスピーカーの話題中心に、Voiceflowの日本語情報を発信してます。たまにAWSやkubernetesなど。

〜スマートスピーカーやVoiceflowの記事は右メニューのカテゴリからどうぞ。〜

jq の to_entries が超便利

とある目的で気象庁のアメダス情報のJSONデータをゴニョゴニョしているのですが、まずアメダス情報のJSONはこういう感じになってる。

$ curl -s https://www.jma.go.jp/bosa20221101000000.json | jq | head -100
{
  "11001": {
    "temp": [
      6.9,
      0
    ],
    "humidity": [
      93,
      0
    ],
    "snow1h": [
      0,
      null
    ],
    "snow6h": [
      0,
      null
    ],
    "snow12h": [
      0,
      null
    ],
    "snow24h": [
      0,
      null
    ],
    "sun10m": [
      0,
      0
    ],
    "sun1h": [
      0,
      0
    ],
    "precipitation10m": [
      0,
      0
    ],
    "precipitation1h": [
      0,
      0
    ],
    "precipitation3h": [
      0,
      0
    ],
    "precipitation24h": [
      0,
      0
    ],
    "windDirection": [
      9,
      0
    ],
    "wind": [
      4.5,
      0
    ]
  },
  "11016": {
    "pressure": [
      1024.3,
      0
    ],
    "normalPressure": [
      1025.8,
      0
    ],
(snip)

数字のキーの下に天気予報や気温などのデータが入っている。このキーが観測所のキーになってる。

観測所は別のJSONで参照できる。こんな感じで。

$ curl -s https://www.jma.go.jp/bosai/amedas/const/amedastable.json | jq
{
  "11001": {
    "type": "C",
    "elems": "11112010",
    "lat": [
      45,
      31.2
    ],
    "lon": [
      141,
      56.1
    ],
    "alt": 26,
    "kjName": "宗谷岬",
    "knName": "ソウヤミサキ",
    "enName": "Cape Soya"
  },
  "11016": {
    "type": "A",
    "elems": "11111111",
    "lat": [
      45,
      24.9
    ],
    "lon": [
      141,
      40.7
    ],
    "alt": 3,
    "kjName": "稚内",
(snip)

で、特定の観測所名のキーが取れれば、その地点のアメダス情報が取れるんだけど、この観測所のIDがキーになってるのが難しいところ。

例えばこうやってみる。

$ curl -s https://www.jma.go.jp/bosai/amedas/const/amedastable.json | jq 'select(.[].kjName == "札幌")'
{
  "11001": {
    "type": "C",
    "elems": "11112010",
    "lat": [
      45,
      31.2
    ],
    "lon": [
      141,
      56.1
    ],
    "alt": 26,
    "kjName": "宗谷岬",
    "knName": "ソウヤミサキ",
    "enName": "Cape Soya"
  },
(snip)
  "14163": {
    "type": "A",
    "elems": "11111111",
    "lat": [
      43,
      3.6
    ],
    "lon": [
      141,
      19.7
    ],
    "alt": 17,
    "kjName": "札幌",
    "knName": "サッポロ",
    "enName": "Sapporo"
  },
(snip)

このJSONは一つの大きなオブジェクトになっているので、下位の階層でselectしても上位からたどったデータが全部表示されてしまう。

次にこれ。

$ curl -s https://www.jma.go.jp/bosai/amedas/const/amedastable.json | jq '.[] | select(.kjName == "札幌")'
{
  "type": "A",
  "elems": "11111111",
  "lat": [
    43,
    3.6
  ],
  "lon": [
    141,
    19.7
  ],
  "alt": 17,
  "kjName": "札幌",
  "knName": "サッポロ",
  "enName": "Sapporo"
}

配列の皮むきというか殻割りというみたいだけど、1階層展開してしまうと今度はキーが取れなくなってしまう。

そこでto_entriesを使う。

These functions convert between an object and an array of key-value pairs. If to_entries is passed an object, then for each k: v entry in the input, the output array includes {"key": k, "value": v}.

to_entriesを使うと、オブジェクトをキーと値の配列に変換してくれて、かつ、"key"と"value"というキー名を追加してくれる。

$ curl -s https://www.jma.go.jp/bosai/amedas/const/amedastable.json | jq '. | to_entries'
[
  {
    "key": "11001",
    "value": {
      "type": "C",
      "elems": "11112010",
      "lat": [
        45,
        31.2
      ],
      "lon": [
        141,
        56.1
      ],
      "alt": 26,
      "kjName": "宗谷岬",
      "knName": "ソウヤミサキ",
      "enName": "Cape Soya"
    }
  },
  {
    "key": "11016",
    "value": {
      "type": "A",
      "elems": "11111111",
      "lat": [
        45,
        24.9
      ],
(snip)

これで観測所名を元に観測所IDを取得することができる。

$ curl -s https://www.jma.go.jp/bosai/amedas/const/amedastable.json | jq '. | to_entries[] | select(.value.kjName == "札幌")'
{
  "key": "14163",
  "value": {
    "type": "A",
    "elems": "11111111",
    "lat": [
      43,
      3.6
    ],
    "lon": [
      141,
      19.7
    ],
    "alt": 17,
    "kjName": "札幌",
    "knName": "サッポロ",
    "enName": "Sapporo"
  }
}

めっちゃ便利。

ということで、観測所名を引数で風向き・風速を返してくれるサンプルをbashで書いてみた。

gist.github.com

$ ./getWindInfo.sh 東京
東京 の風向きは北、風速 2.2 メートルです
$ ./getWindInfo.sh 大阪
大阪 の風向きは北北東、風速 3.2 メートルです

参考