jq:使用不必要的嵌套级别展平对象

时间:2017-05-02 13:59:58

标签: json mongodb jq

我面临着拥有一个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?

谢谢!

1 个答案:

答案 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