我面临着拥有一个json文件的问题,其中相同的密钥有时具有平坦的值,而其他的则具有额外的嵌套(并且为了我的目的不必要)级别,其然后包括相关值。
该文件是换行符分隔,我试图摆脱任何额外的级别。到目前为止,只有当嵌套级别出现在树的第一个分支中时,我才能成功地使用
jq -c '[.] | map(.[] |= if type == "object" and (.number | length) > 0 then .numberLong else . end) | .[]' mongoDB.json
以下示例进一步说明了这一点。我最初的所作所为:
{
"name": "John",
"age": {
"numberLong": 22
}
}
{
"name": "Jane",
"age": 24
}
{
"name": "Dennis",
"age": 34,
"details": [
{
"telephone_number": 555124124
}
]
}
{
"name": "Frances",
"details": [
{
"telephone_number": {
"numberLong": 444245523
}
}
]
}
我的脚本执行的操作(忽略第二个numberLong
):
{
"name": "John",
"age": 22
},
{
"name": "Jane",
"age": 24
}
{
"name": "Dennis",
"age": 34,
"details": [
{
"telephone_number": 555124124
}
]
}
{
"name": "Frances",
"details": [
{
"telephone_number": {
"numberLong": 444245523
}
}
]
}
我实际上希望实现的目标(递归地将所有numberLong
个键的值复制一级,无论它们在文件中的位置如何):
[
{
"name": "John",
"age": 22
},
{
"name": "Jane",
"age": 24
},
{
"name": "Dennis",
"age": 34,
"details": [
{
"telephone_number": 555124124
}
]
},
{
"name": "Frances",
"details": [
{
"telephone_number": 444245523
}
]
}
]
此转换是日常管道的一部分,适用于大小高达70GB的多个文件,因此在遍历文件时速度可能会成为问题。问题源于MongoDB的不同类型:MongoDB differences between NumberLong and simple Integer?
谢谢!
答案 0 :(得分:3)
如果你的jq有'walk / 1'那么最简单的完全通用解决方案就是这样:
walk( if type=="object"
then with_entries( if .value | (type == "object" and has("numberLong"))
then .value |= .numberLong
else . end)
else . end )
如果你的jq没有'walk',那么最好升级,因为这也会提高速度;否则你可以google for jq。
如果这对于非常大的文件来说太慢,您可能需要追踪需要转换的精确位置,以避免完全通用方法的开销。
您的示例(“我最初拥有的”)提供了一个对象流,因此值得指出的是,由于jq是面向流的,因此处理由JSON实体流组成的非常大的文件(aka “文件”)不是单独的那么大。
(一个近似的经验法则是,如果输入中最大的JSON实体具有N个单位的大小,并且如果jq创建的最大JSON实体具有大小为M个单位,那么jq可能需要访问大约M + N + max (M,N)单位的记忆。)
要处理包含单个JSON数组的非常大的文件,建议首先生成顶级元素流以供后续处理。
在最糟糕的情况下(一个包含一个非常大的复杂JSON文档的非常大的文件),您可能必须使用流式解析器,例如jq所具有的。
有关处理非常大的文件的各种技术的说明,请参阅 Process huge GEOJson file with jq