简体   繁体   English

使用 jq 展平 JSON 文档

[英]Flatten a JSON document using jq

I'm considering the following array of JSON objects:我正在考虑以下 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"
      ]
    }
  }
]

and I would like to flatten it to get:我想将其展平以获得:

[
  {
    "index": "index1",
    "type": "type",
    "id": "id1",
    "deviceOs": "Android",
    "deviceID": "deviceID1",
    "country": "DE"
  },
  {
    "index": "index2",
    "type": "type",
    "id": "id2",
    "deviceOs": "Android",
    "deviceID": "deviceID2",
    "country": "US"
  }
]

I'm trying to work with jq but I fail to flatten the "fields" .我正在尝试与jq合作,但我无法展平"fields" How should I do it?我应该怎么做? At the moment I'm interested in command-line tools, but I'm open to other suggestions as well.目前我对命令行工具很感兴趣,但我也愿意接受其他建议。

This one was a tricky one to craft. 这个是一个棘手的工艺。

map
(
    with_entries(select(.key != "fields"))
    +
    (.fields | with_entries(.value = .value[0]))
)

Let's break it down and explain the bits of it 让我们分解并解释它的各个部分

  1. For every item in the array... 对于阵列中的每个项目......

     map(...) 
  2. Create a new object containing the values for all except the fields property. 创建一个新对象,其中包含除fields属性之外的所有值。

     with_entries(select(.key != "fields")) 
  3. Combine that with... 结合......

     + 
  4. Each of the fields projecting each of the values to the first item of each array 每个fields每个值投影到每个数组的第一项

     (.fields | with_entries(.value = .value[0])) 

You can use this filter: 您可以使用此过滤器:

[.[] | {index: .index, type: .type, id: .id, deviceOs: .fields.deviceOs[],deviceID: .fields.deviceID[],country: .fields.country[]}]

You can test here https://jqplay.org 你可以在这里测试https://jqplay.org

Here are some variations that start by merging .fields into the containing object with + and then flattening the array elements. 下面是一些变体,首先将.fields合并到包含对象中,然后展开数组元素。 First we take care of .fields with 首先我们照顾.fields

  .[]
| . + .fields
| del(.fields)

that leaves us with objects which look like 这让我们看起来像是一样的物体

{
  "index": "index1",
  "type": [
    "type"
  ],
  "id": "id1",
  "deviceOs": [
    "Android"
  ],
  "deviceID": [
    "deviceID1"
  ],
  "country": [
    "DE"
  ]
}

then we can flatten the keys multiple ways. 然后我们可以多种方式压扁键。 One way is to use with_entries 一种方法是使用with_entries

| with_entries( .value = if .value|type == "array" then .value[0] else .value end )

another way is to use reduce and setpath 另一种方法是使用reducesetpath

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

There's a tool called gron and you can pipe that json in, to get something like this. 有一个名为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";

Similar to the @jq170727 anwser:类似于@jq170727 anwser:

jq 'map(. + (.fields | with_entries(.value |= .[])) | del(.fields))'

(assuming no field inside .fields is itself called .fields ). (假设.fields中没有字段本身称为.fields )。

The |with_entries(.value|=.[]) part is to flatten the value arrays in .fields -- beware only the first item is preserved. |with_entries(.value|=.[])部分是将 .fields 中的值.fields展平——注意只保留第一项。 .value|=join(", ") could be used to join multiple string values into one. .value|=join(", ")可用于将多个字符串值合并为一个。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM