使用jq展平JSON文档

Dro*_*ror 16 json jq

我正在考虑以下JSON对象数组:

[
  {
    "index": "index1",
    "type": "type1",
    "id": "id1",
    "fields": {
      "deviceOs": [
        "Android"
      ],
      "deviceID": [
        "deviceID1"
      ],
      "type": [
        "type"
      ],
      "country": [
        "DE"
      ]
    }
  },
  {
    "index": "index2",
    "type": "type2",
    "id": "id2",
    "fields": {
      "deviceOs": [
        "Android"
      ],
      "deviceID": [
        "deviceID2"
      ],
      "type": [
        "type"
      ],
      "country": [
        "US"
      ]
    }
  }
]
Run Code Online (Sandbox Code Playgroud)

我想弄平它得到:

[
  {
    "index": "index1",
    "type": "type",
    "id": "id1",
    "deviceOs": "Android",
    "deviceID": "deviceID1",
    "country": "DE"
  },
  {
    "index": "index2",
    "type": "type",
    "id": "id2",
    "deviceOs": "Android",
    "deviceID": "deviceID2",
    "country": "US"
  }
]
Run Code Online (Sandbox Code Playgroud)

我正在尝试与之合作,jq但我没有将其弄平"fields".我该怎么办?目前我对命令行工具感兴趣,但我也对其他建议持开放态度.

Jef*_*ado 31

这个是一个棘手的工艺.

map
(
    with_entries(select(.key != "fields"))
    +
    (.fields | with_entries(.value = .value[0]))
)
Run Code Online (Sandbox Code Playgroud)

让我们分解并解释它的各个部分

  1. 对于阵列中的每个项目......

    map(...)
    
    Run Code Online (Sandbox Code Playgroud)
  2. 创建一个包含除fields属性之外的所有值的新对象.

    with_entries(select(.key != "fields"))
    
    Run Code Online (Sandbox Code Playgroud)
  3. 结合......

    +
    
    Run Code Online (Sandbox Code Playgroud)
  4. 每个fields值将每个值投影到每个阵列的第一项

    (.fields | with_entries(.value = .value[0]))
    
    Run Code Online (Sandbox Code Playgroud)

  • 很好的答案。我要添加的一小部分是连接,因为硬编码的列表索引让我担心丢失的东西。`with_entries(.value = (.value| join(",")))` https://jqplay.org/s/2mY6yus7Mz (2认同)

sun*_*386 6

有一个名为的工具gron,您可以通过管道将该 json 导入,以获得类似的内容。

$ gron document.json
json = [];
json[0] = {};
json[0].fields = {};
json[0].fields.country = [];
json[0].fields.country[0] = "DE";
json[0].fields.deviceID = [];
json[0].fields.deviceID[0] = "deviceID1";
json[0].fields.deviceOs = [];
json[0].fields.deviceOs[0] = "Android";
json[0].fields.type = [];
json[0].fields.type[0] = "type";
json[0].id = "id1";
json[0].index = "index1";
json[0].type = "type1";
json[1] = {};
json[1].fields = {};
json[1].fields.country = [];
json[1].fields.country[0] = "US";
json[1].fields.deviceID = [];
json[1].fields.deviceID[0] = "deviceID2";
json[1].fields.deviceOs = [];
json[1].fields.deviceOs[0] = "Android";
json[1].fields.type = [];
json[1].fields.type[0] = "type";
json[1].id = "id2";
json[1].index = "index2";
json[1].type = "type2";

Run Code Online (Sandbox Code Playgroud)

  • 这太棒了!这个答案对我来说效果更好,因为它本质上可以递归任意数量的级别。例如,这里 `deviceID[.] = \"(.+)\";$` 成为一个 grep 表达式,用于在不同深度的整个输出树中查找“叶子”。谢谢。 (4认同)

abo*_*uso 5

您可以使用以下过滤器:

[.[] | {index: .index, type: .type, id: .id, deviceOs: .fields.deviceOs[],deviceID: .fields.deviceID[],country: .fields.country[]}]
Run Code Online (Sandbox Code Playgroud)

您可以在这里测试https://jqplay.org


jq1*_*727 5

以下是一些变体,首先使用 + 将 .fields 合并到包含对象中,然后展平数组元素。首先我们处理 .fields

  .[]
| . + .fields
| del(.fields)
Run Code Online (Sandbox Code Playgroud)

这给我们留下了看起来像的物体

{
  "index": "index1",
  "type": [
    "type"
  ],
  "id": "id1",
  "deviceOs": [
    "Android"
  ],
  "deviceID": [
    "deviceID1"
  ],
  "country": [
    "DE"
  ]
}
Run Code Online (Sandbox Code Playgroud)

然后我们可以通过多种方式展平按键。一种方法是使用with_entries

| with_entries( .value = if .value|type == "array" then .value[0] else .value end )
Run Code Online (Sandbox Code Playgroud)

另一种方法是使用reducesetpath

| . as $v
| reduce keys[] as $k (
    {};
    setpath([$k]; if $v[$k]|type != "array" then $v[$k] else $v[$k][0] end)
  )
Run Code Online (Sandbox Code Playgroud)