jq的意外循环周期

时间:2019-05-09 18:49:30

标签: json jq

我正在尝试使用jq从bash中将表打印到stdout:

[
    {
      "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
          }
        ]
      }
    }
]

通过jq -r '(.[].key + " " + .[].values_over_time[][].key_as_string) + " " + (.[].values_over_time[][].doc_count|tostring)',我得到了以下结果:

"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"

附加的循环级别有些奇怪,我希望只看到3行:

"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"

阅读jq文档,但无法理解正确整齐地进行正确迭代的正确方法。你有什么线索吗?

JQplay code sample

3 个答案:

答案 0 :(得分:1)

您要扩展values_over_time两次,因此将生成3 * 3 = 9个输出。做类似这样的事情:

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

比较这两个命令以清楚地看出差异:

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

答案 1 :(得分:0)

技术原因是您要组合会生成多个结果的表达式。而jq的运行方式,将为这些子表达式的每种组合生成结果。

看看您的过滤器和输入,这是每个子表达式生成多少个结果:

(.[].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

这就是为什么您必须始终务必小心使用产生多个结果的表达式(例如[])。

正如Oguz所指出的那样,您需要编写它,使得输入仅在表达式中扩展一次。通常最好在过滤器的开头。

这可以通过多种方式完成,我会这样写:

.[] | "\(.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

答案 2 :(得分:0)

或者,可以使用基于步行路径的unix实用程序 jtc 构建相同的表(其中,将取回值的逻辑编码到步行路径中):< / p>

bash $ <file.json jtc -w'[:][key]<k>v[-1]<key_as_string>l:<s>v[-1][doc_count]' -T'"{k} {s} {}"'
"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"
bash $ 

分解步行路径(-w

  • [:]-遍历每个JSON元素(从顶部/根开始)
  • [key]<k>v-然后处理key记录并在k名称空间中存储其值
  • [-1]<key_as_string>l:<s>v-上一级备份(寻址父级),并在该父JSON中找到标签为key_as_string的每个(所有)元素,并记住s命名空间中的每个值< / li>
  • [-1][doc_count]-通过doc_count
  • 备份1级地址

-插值结果走动(最后一个值为doc_count),并按照模板将其保留在命名空间ks

PS>披露:我是jtc工具的创建者