26

次の 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"
      ]
    }
  }
]

そして、それを平らにして取得したいと思います:

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

で作業しようとしていますjqが、を平坦化できません"fields"。どうすればいいですか?現時点では、コマンドライン ツールに興味がありますが、他の提案も受け付けています。

4

5 に答える 5

41

これは作るのが難しいものでした。

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

それを分解して、そのビットを説明しましょう

  1. 配列内のすべてのアイテムについて...

    map(...)
    
  2. プロパティを除くすべての値を含む新しいオブジェクトを作成しfieldsます。

    with_entries(select(.key != "fields"))
    
  3. それを組み合わせて...

    +
    
  4. fields値を各配列の最初の項目に射影する

    (.fields | with_entries(.value = .value[0]))
    
于 2014-07-12T06:32:45.063 に答える
8

このフィルターを使用できます。

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

ここでテストできますhttps://jqplay.org

于 2014-08-30T19:17:37.760 に答える
4

.fields を含むオブジェクトに + でマージし、配列要素をフラット化することから始まるいくつかのバリエーションを次に示します。最初に .fields を処理します

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

それは私たちに次のように見えるオブジェクトを残します

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

次に、複数の方法でキーをフラット化できます。1 つの方法はwith_entriesを使用することです

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

もう 1 つの方法は、reducesetpathを使用することです

| . as $v
| reduce keys[] as $k (
    {};
    setpath([$k]; if $v[$k]|type != "array" then $v[$k] else $v[$k][0] end)
  )
于 2017-08-02T17:05:26.717 に答える
1

@jq170727 アンサーに似ています:

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

(内部のフィールド.fields自体が呼び出されていないと仮定します.fields)。

部分は、値の|with_entries(.value|=.[])配列を平坦化すること.fieldsです。最初の項目のみが保持されることに注意してください。.value|=join(", ")複数の文字列値を 1 つに結合するために使用できます。

于 2021-09-21T15:16:04.993 に答える