ようへいの日々精進XP

よかろうもん

JSON キーに Dot(.) が含まれている場合、どうやって jq でパースするのか

例えば

Elasticsearch の Index Mapping を確認したい場合。

curl -s localhost:9200/debug-2017.06.23/_mapping

以下のようなレスポンスが返ってくる。

{
  "debug-2017.06.23": {
    "mappings": {
      "debug-apilog": {
        "properties": {
          "@timestamp": {
            "type": "date"
...

冒頭のキー debug-2017.06.23 は要らないので、以下のように jq でパースしようとすると…

$ curl -s localhost:9200/debug-2017.06.23/_mapping | jq '.debug-2017.06.23'
jq: error: Invalid numeric literal at EOF at line 1, column 10 (while parsing '2017.06.23') at <top-level>, line 1:
.debug-2017.06.23
jq: 1 compile error
(23) Failed writing body

あれ?ってなった。

色々と試してみるも…

$ curl -s localhost:9200/debug-2017.06.23/_mapping | jq ".debug-2017.06.23"
jq: error: Invalid numeric literal at EOF at line 1, column 10 (while parsing '2017.06.23') at <top-level>, line 1:
.debug-2017.06.23
jq: 1 compile error
(23) Failed writing body

$ curl -s localhost:9200/debug-2017.06.23/_mapping | jq ."debug-2017.06.23"
jq: error: Invalid numeric literal at EOF at line 1, column 10 (while parsing '2017.06.23') at <top-level>, line 1:
.debug-2017.06.23
jq: 1 compile error
(23) Failed writing body

うーむ。

ドキュメントを見る

ドキュメント には以下のように書かれていた。

Object Identifier-Index: .foo, .foo.bar

The simplest useful filter is .foo. When given a JSON object (aka dictionary or hash) as input, it produces the value at the key “foo”, or null if there’s none present.

...(snip)

For example .["foo::bar"] and .["foo.bar"] work while .foo::bar does not, and .foo.bar means .["foo"].["bar"]

どうやら、["debug-2017.06.23"] とすれば良さそう。

挙動を確認してみる。

#
# jq のバージョン
#
$ jq --version
jq-1.5

#
# シンプルなフィルタ
#
$ echo '{"foo":"bar"}' | jq .
{
  "foo": "bar"
}

$ echo '{"foo":{"bar":"baz"}}' | jq '.foo.bar'
"baz"

#
# jq 的には .foo|.bar と同義
#
$ echo '{"foo.bar":"baz"}' | jq .foo.bar
null

#
# なんかおかしい
#
$ echo '{"foo.bar":"baz"}' | jq .["foo.bar"]
{
  "foo.bar": "baz"
}
"baz"

#
# うまくいった
#
$ echo '{"foo.bar":"baz"}' | jq '.["foo.bar"]'
"baz"

#
# これでもうまくいった
#
$ echo '{"foo.bar":"baz"}' | jq '."foo.bar"'
"baz"

ということで

冒頭の Elasticsearch Index の mapping 確認については、以下のように書けば良さそうということが解った。

curl -s localhost:9200/debug-2017.06.23/_mapping | jq '.["debug-2017.06.23"]'

もしくは

curl -s localhost:9200/debug-2017.06.23/_mapping | jq '."debug-2017.06.23"'

以下のように意図した出力になった。

{
  "mappings": {
    "debug-apilog": {
      "properties": {
        "@timestamp": {
          "type": "date"
        },
        "@version": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 256
...

めでたし、めでたし。

参考

有難うございました。