jqを使用して、特定の接続キーに基づいて非常に大きなJSONファイルを分割します。

jqを使用して、特定の接続キーに基づいて非常に大きなJSONファイルを分割します。

これらのキー(および他のいくつかのキー)を含む数百万のエントリを含む配列を含む非常に大きなJSONファイルがあるとします。

 {
        "name": "assets/fUCcxWczWT0",
        "displayName": "The House",
        "authorName": "John Smith",
        "resources": {"house" : "address","car":"bla"},
 }

jq特定の名前キーの前にあるコンテンツをスライス(削除)する方法は?たとえば、一意に識別される要素より前のものです"name": "assets/fUCcxWczWT0"

上記は、文書の代表的な要素を単純化したものです。最上位配列の実際の要素は次のとおりです。

{
  "name": "assets/4vds6twPsb7",
  "displayName": "pim",
  "authorName": "Erwin Braak",
  "createTime": "2017-12-06T11:52:40.557236Z",
  "updateTime": "2020-10-07T09:49:08.752848Z",
  "formats": [
    {
      "root": {
        "relativePath": "Pim.gltf",
        "url": "https://poly.googleapis.com/downloads/fp/1602064148752848/4vds6twPsb7/c8Ksvo0_VjG/Pim.gltf",
        "contentType": "model/gltf+json"
      },
      "resources": [
        {
          "relativePath": "Pim.bin",
          "url": "https://poly.googleapis.com/downloads/fp/1602064148752848/4vds6twPsb7/c8Ksvo0_VjG/Pim.bin",
          "contentType": "application/octet-stream"
        },
        {
          "relativePath": "C:/Users/PC/Desktop/pom/pimSurface_Color.png",
          "url": "https://poly.googleapis.com/downloads/fp/1602064148752848/4vds6twPsb7/c8Ksvo0_VjG/C:/Users/PC/Desktop/pom/pimSurface_Color.png",
          "contentType": "image/png"
        }
      ],
      "formatComplexity": {
        "triangleCount": "586149"
      },
      "formatType": "GLTF2"
    },
    {
      "root": {
        "relativePath": "Pim.obj",
        "url": "https://poly.googleapis.com/downloads/fp/1602064148752848/4vds6twPsb7/5QVGpvfauVK/Pim.obj",
        "contentType": "text/plain"
      },
      "resources": [
        {
          "relativePath": "Pim.mtl",
          "url": "https://poly.googleapis.com/downloads/fp/1602064148752848/4vds6twPsb7/5QVGpvfauVK/Pim.mtl",
          "contentType": "text/plain"
        },
        {
          "relativePath": "C:/Users/PC/Desktop/pom/pimSurface_Color.png",
          "url": "https://poly.googleapis.com/downloads/fp/1602064148752848/4vds6twPsb7/5QVGpvfauVK/C:/Users/PC/Desktop/pom/pimSurface_Color.png",
          "contentType": "image/png"
        }
      ],
      "formatComplexity": {
        "triangleCount": "586149"
      },
      "formatType": "OBJ"
    }
  ],
  "thumbnail": {
    "relativePath": "4vds6twPsb7.png",
    "url": "https://lh3.googleusercontent.com/C_il4QubLWYMAyrnGPMjXWx4E7MVYLZAoX_Hf-qr4WyHfebvf2y3lndh71A350g",
    "contentType": "image/png"
  },
  "license": "CREATIVE_COMMONS_BY",
  "visibility": "PUBLIC",
  "isCurated": true,
  "presentationParams": {
    "orientingRotation": {
      "w": 1
    },
    "colorSpace": "LINEAR",
    "backgroundColor": "#eeeeee"
  }
}

ベストアンサー1

ファイルサイズの問題に加えて、効果的なソリューションを妨げる主な障害は次のとおりですjqみんなオブジェクト、これは配列も処理されることを意味します。誰でも全体的にまたは何もありません。したがって、要素を含む大きな大きな配列を削除しなければ、後者を元の入力から(はるかに小さい)オブジェクトのストリームとして扱うことができます。含む、最終出力。

これを達成するには、jq最終出力配列にも配列処理機能が使用されないように、いくつかのテキスト操作が必要です。いくつかのバリエーションを考えることができますが、各バリアントにはテキスト操作で実行する必要がある程度の作業がありますが、この操作を配列構造構文の最終出力のみを追加する最小限の操作に制限することを選択しました。

このテキスト操作は非常に最小限に抑えられ、この目的のために独自のテキスト設定を使用できますjq。これにより、他のツールに頼らずに純粋なソリューションを持つことができるだけでなく、jq必要なテキストビットストリームフローに沿って追加することもできます。予想されるインデント/改行やその他の形式の仮定に依存せず、これはすべて「手動で」最終出力配列を構築するより強力な方法を容易にします。これらの利点の対価はsed

入力例の「行」は次のとおりです。

jq -rn --stream --arg f name --arg q 'assets/fUCcxWczWT0' '"[", foreach fromstream(1|truncate_stream(inputs)) as $o ([null,null]; if .[1] or $o[$f]? == $q then [.[1], ","] else . end; .[0]//empty, if .[1] then $o else empty end), "]"'

使用されたオプションjq。正しい結果を得るには、最初の3つが必要です。

  • -r任意のテキストを出力するときに生(JSONに変換されないなど)
  • -n内蔵消費によるinputs入力データの場合ただjqそれ以外の場合は、入力の最初のオブジェクト全体が次の一般的なループによって与えられます。
  • --streamjqセルフストリーミングモードを使用して入力を消費するために使用されます。
  • --arg f name探している値を含むフィールドの名前
  • --arg q 'assets/fUCcxWczWT0'各オブジェクトのフィールドで探している値

jq拡張機能や説明など、スクリプトを個別に確認してください。

# Firstly, the initial bit of arbitrary text: the opening bracket for the final output,
# as required for a valid JSON array syntax

"[",

# Then a foreach statement, looping over the objects provided singularly, one by one,
# by the streamlined input
# NOTE 1: jq's streaming mode is used for this solution primarily so that we
#         can use `1 | truncate_stream()` here, which courteously (and natively)
#         strips the first (1 | ...) structure of the original input along the course of
#         the streamlined operation.
#         The first structure is obviously the main huge array containing the
#         objects, hence we receive these latter singularly in a truly streamlined
#         fashion, freed by the containment of the array
# NOTE 2: using `inputs | tostream` here in place of `--stream`, although functioning,
#         would not obtain the streaming goal, because it would first take the entire
#         input as a whole rather than streaming it from the start
    foreach fromstream( 1|truncate_stream(inputs) ) as $o (
        # the initial state of the loop: we use 2 values as a "shifting 2-value state-machine"
        # for the comma to be output (as text) along with all the elements except the
        # first. We use the second value as an overall state too
        [null, null];
        # here we look for the wanted value in the wanted field unless already found
        # previously according to the overall state, and we update the loop state "shifting"
        # the 2-state for the comma as soon as the wanted value is found
        if .[1] or $o[$f]? == $q then [.[1], ","] else . end;
        # here we print the comma text (if need be according to its 2-state)
        # as required for separating elements in a JSON array syntax, then we print
        # the object element itself if the overall state says so
        .[0]//empty, if .[1] then $o else empty end
    ),

# Lastly, the final bit of arbitrary text: the closing bracket for the output,
# as required for a valid JSON array syntax

"]"

いくつかの最終注意事項:

  • 明らかに、このアプローチは元の入力が巨大ではありますが、基本的に単純で単純であると仮定しています(実際にこれを利用します)。内部値と外部値の間の相互参照を持つより複雑な全体構造であれば、スクリプトに簡単に必要になることがあります。同じようにもっと複雑で難しくなる
  • 要素を出力したい場合に従って代わりに、から始まる必要に応じて、ストリーミングロジックはより簡単になり、状態がまったく必要ない場合があります。原則として、目的haltのオブジェクトが見つかったときにスクリプトのみを書くことができるので、副作用はより速くなります(完全ストリーミング操作)。

おすすめ記事