unexpected loop cycles with jq

懵懂的女人 提交于 2021-01-28 08:47:18

问题


I'm trying to print a table in bash to stdout from json with jq:

[
    {
      "key": "name",
      "doc_count": 1000,
      "values_over_time": {
        "buckets": [
          {
            "key_as_string": "2019-05-01 11:00:00.000",
            "key": 1556708400000,
            "doc_count": 50
          },
          {
            "key_as_string": "2019-05-02 12:00:00.000",
            "key": 1556798400000,
            "doc_count": 40
          },
          {
            "key_as_string": "2019-05-02 13:00:00.000",
            "key": 1556802000000,
            "doc_count": 30
          }
        ]
      }
    }
]

With jq -r '(.[].key + " " + .[].values_over_time[][].key_as_string) + " " + (.[].values_over_time[][].doc_count|tostring)' I get these results:

"name 2019-05-01 11:00:00.000 50"
"name 2019-05-02 12:00:00.000 50"
"name 2019-05-02 13:00:00.000 50"
"name 2019-05-01 11:00:00.000 40"
"name 2019-05-02 12:00:00.000 40"
"name 2019-05-02 13:00:00.000 40"
"name 2019-05-01 11:00:00.000 30"
"name 2019-05-02 12:00:00.000 30"
"name 2019-05-02 13:00:00.000 30"

There is something strange with additional loop level as I expect to see only 3 lines:

"name 2019-05-01 11:00:00.000 50"
"name 2019-05-02 12:00:00.000 40"
"name 2019-05-02 13:00:00.000 30"

Read jq docs but wasn't able to understand the right way to iterate in a proper in a neat way. Do you have any clues?

JQplay code sample


回答1:


You're expanding values_over_time twice, thus 3 * 3 = 9 outputs are generated. Do something like this instead:

.[] | .key + " " + (.values_over_time.buckets[] | "\(.key_as_string) \(.doc_count)")

Compare these two commands to see the difference clearly:

$ jq -nc '[1,2,3] | [.[]*.[]]'
[1,2,3,2,4,6,3,6,9]
$ jq -nc '[1,2,3] | [.[]|.*.]'
[1,4,9]



回答2:


The technical reason is that you're combining expressions that generate multiple results. And the way jq operates, it will generate results for every combination of those subexpressions.

Looking at your filter and your input, here's how many results are generated by each subexpression:

(.[].key + " " + .[].values_over_time[][].key_as_string) + " " + (.[].values_over_time[][].doc_count|tostring)
(1         1     3)                                        1     (3                                 | 1)
(1 * 1 * 3 = 3)                                            1     (3 * 1 = 3)
 3 * 1 * 3 = 9

This is why you must always take care in using expressions that generate multiple results (e.g., []).

As Oguz points out, you need to write it such that the input is expanded only once in the expression. Usually right at the beginning of the filter is best.

This could be done in many ways, I would write it like so:

.[] | "\(.key) \(.values_over_time.buckets[] | "\(.key_as_string) \(.doc_count)")"
1   |   (1)     (3                           |   (1)               (1))
1   |   (1)     (3                           | 1 * 1 = 1)
1   |   (1)     (3 * 1 = 3)
1   | (1 * 3 = 3)
1 * 3 = 3


来源:https://stackoverflow.com/questions/56065822/unexpected-loop-cycles-with-jq

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!