如何在一个大型json文件中选择特定的数据,并以相同的结构保存结果



像这样的超大Json文件(3Gb(:

{
"listPoint": [{
"Paime": "RE6845",
"rmOi": "SNO-55",
"State": "OPEN",
"dateOpneing": "2017-12-22",
"adress": {
"ZIPCODE": "33410",
"codeRoc": "33105"
}
},
{
"Paime": "RE6243",
"rmOi": "SNO-65",
"State": "OPEN",
"dateOpneing": "2014-11-12",
"adress": {
"ZIPCODE": "453410",
"codeRoc": "35105"
}
}
]
}

我正在尝试将其过滤到另一个具有相同结构的文件中,条件是所有ZIPCODES都必须属于一个特定的列表:

['33410', '42000', '75015'....]

结果应该是这样的(输出文件必须具有与输入相同的结构(:

{
"listPoint": [{
"Paime": "RE6845",
"rmOi": "SNO-55",
"State": "OPEN",
"dateOpneing": "2017-12-22",
"adress": {
"ZIPCODE": "33410",
"codeRoc": "35105"
},

{
"Paime": "RE6243",
"rmOi": "SNO-65",
"State": "OPEN",
"dateOpneing": "2014-11-12",
"ZIPCODE": "75015",
"codeRoc": "55115"
}
.....

]
}

我试过了,但它流式传输了所有文件:

./jq-win64.exe -n --stream 'fromstream(0|truncate_stream(inputs))' test1.json

我不知道该怎么做,你能帮吗

(1(如果您的计算机有足够的RAM,那么最简单的解决方案是:

< very-large-file.json jq '
.listPoint |= map(select(.ZIPCODE|startswith("33")))'

(2( 否则,您可以在两步解决方案中使用jq的流式解析器,例如:

< very-large-file.json jq -n --stream '
fromstream(2|truncate_stream(inputs))
| select(.ZIPCODE|startswith("33"))' |
jq -s '{listPoint: .}'

在第一步中,生成一个相关JSON对象流;在第二个步骤中,将它们重新组装成所需的结构。

(3( 如果即使是筛选出的数组也太大,无法放入内存,那么你可能会做得比更糟

echo '{listPoint:'
< very-large-file.json jq -n --stream '
fromstream(2|truncate_stream(inputs))
| select(.ZIPCODE|startswith("33"))' |
jq -ncr 'input, (inputs | ",", .)'
echo '}'

(4( 如果您想根据白名单选择邮政编码,请将选择标准更改为

.ZIPCODE|IN($whitelist[])

-----

注意:如果你的shell不够像bash,你可能会发现最好使用以下调用格式:

jq OPTIONS -f program.jq INPUT.json

对于记录,避免文件大小问题的另一种方法是使用配套工具,如jm(JSON机器的包装脚本(或jm.py(ijson Python库的包装脚本

jm --pointer /listPoint large.json |
jq -n '["33410", "42000", "75015"] as $ok
| {listPoint: [inputs | select(.adress.ZIPCODE|IN($ok[]))]} '

jm.py -i listPoint.item large.json |
jq -n '["33410", "42000", "75015"] as $ok
| {listPoint: [inputs | select(.adress.ZIPCODE|IN($ok[]))]} '

我通常发现jm在时间和空间上都更经济,但安装它需要一些工作

免责声明:我是这两个包装器脚本的作者,它们正是为处理这样的情况而创建的。

最新更新