使用jq处理大型JSON流

时间:2016-08-30 15:51:28

标签: json jq

我从curl获得了一个非常大的JSON流(几GB)并尝试使用jq处理它。

我要用jq解析的相关输出打包在表示结果结构的文档中:

{
  "results":[
    {
      "columns": ["n"],

      // get this
      "data": [    
        {"row": [{"key1": "row1", "key2": "row1"}], "meta": [{"key": "value"}]},
        {"row": [{"key1": "row2", "key2": "row2"}], "meta": [{"key": "value"}]}
      //  ... millions of rows      

      ]
    }
  ],
  "errors": []
}

我想用row提取jq数据。这很简单:

curl XYZ | jq -r -c '.results[0].data[0].row[]'

结果:

{"key1": "row1", "key2": "row1"}
{"key1": "row2", "key2": "row2"}

但是,这总是等到curl完成。

我使用了--stream选项来处理这个问题。我尝试了以下命令,但也等待从curl返回完整对象:

curl XYZ | jq -n --stream 'fromstream(1|truncate_stream(inputs)) | .[].data[].row[]'

有没有办法'跳转'到data字段并逐个解析row而无需等待结束标记?

2 个答案:

答案 0 :(得分:4)

(1)您将使用的香草过滤器如下:

jq -r -c '.results[0].data[].row'

(2)这里使用流解析器的一种方法是使用它来处理.results[0].data的输出,但这两个步骤的组合可能比vanilla方法慢。

(3)要生成所需的输出,您可以运行:

jq -nc --stream '
  fromstream(inputs
    | select( [.[0][0,2,4]] == ["results", "data", "row"])
    | del(.[0][0:5]) )'

(4)或者,您可能希望尝试以下方面:

jq -nc --stream 'inputs
      | select(length==2)
      | select( [.[0][0,2,4]] == ["results", "data", "row"])
      | [ .[0][6], .[1]] '

对于说明性输入,上次调用的输出将为:

["key1","row1"] ["key2","row1"] ["key1","row2"] ["key2","row2"]

答案 1 :(得分:2)

获得:

{"key1": "row1", "key2": "row1"} {"key1": "row2", "key2": "row2"}

自:

{ "results":[ { "columns": ["n"], "data": [
{"row": [{"key1": "row1", "key2": "row1"}], "meta": [{"key": "value"}]}, {"row": [{"key1": "row2", "key2": "row2"}], "meta": [{"key": "value"}]} ] } ], "errors": [] }

执行以下操作,相当于jq -c '.results[].data[].row[]',但使用的是:

jq -cn --stream 'fromstream(1|truncate_stream(inputs | select(.[0][0] == "results" and .[0][2] == "data" and .[0][4] == "row") | del(.[0][0:5])))'

这是做什么的:

  • 将JSON转换为流(使用--stream
  • 选择路径.results[].data[].row[](使用select(.[0][0] == "results" and .[0][2] == "data" and .[0][4] == "row"
  • 放弃路径的初始部分,例如"results",0,"data",0,"row"del(.[0][0:5])
  • 最后使用jq FAQ
  • 中的fromstream(1|truncate_stream(…))模式将生成的jq流重新转换为预期的JSON

例如:

echo '{"results":[{"columns":["n"],"data":[{"row":[{"key1":"row1","key2":"row1"}],"meta":[{"key":"value"}]},{"row":[{"key1":"row2","key2":"row2"}],"meta":[{"key":"value"}]}]}],"errors":[]}' | jq -cn --stream 'fromstream(1|truncate_stream(inputs | select(.[0][0] == "results" and .[0][2] == "data" and .[0][4] == "row") | del(.[0][0:5])))'

产生所需的输出。