フィールドの検索とjqの他のフィールドの置き換え

フィールドの検索とjqの他のフィールドの置き換え

特定のプロパティを持つオブジェクトを検索した後、他のプロパティを更新しようとします。次の入力が与えられた場合:

[
  {
    "replacements": [
      {
        "newValue": "0",
        "yamlPath": "k8s-helm-templates.deployment.containers.abc.image.tag"
      },
      {
        "newValue": "0",
        "yamlPath": "k8s-helm-templates.deployment.containers.def.image.tag"
      },
      {
        "newValue": "0",
        "yamlPath": "k8s-helm-templates.deployment.containers.ghi.image.tag"
      }
    ],
    "yamlFilePath": "k8s/helm/Dev/us-east-1/values.yaml"
  }
]

そして、プレースホルダ(abc-image-tagfor k8s-helm-templates.deployment.containers.abc.image.tag)を次のように使用します。

[
  {"name":"abc-image-tag","value":"123"},
  {"name":"def-image-tag","value":"456"}
]

あなたが得る必要があるのは、与えられた値が正しく置き換えられ、ゼロ値が次のようにフィルタリングされることです。

[
  {
    "replacements": [
      {
        "newValue": "123",
        "yamlPath": "k8s-helm-templates.deployment.containers.abc.image.tag"
      },
      {
        "newValue": "456",
        "yamlPath": "k8s-helm-templates.deployment.containers.def.image.tag"
      }
    ],
    "yamlFilePath": "k8s/helm/Dev/us-east-1/values.yaml"
  }
]

いくつかのトリックを試して文書を調べましたが、うまく動作しないようです。 jqで可能ですか?他の手順を実行するには、bashを使用してください。

ベストアンサー1

この試み:

jq \
--null-input \
--rawfile replacements replacements.json \
--rawfile placeholders placeholders.json \
'
def placeholder_index: .name | gsub("-"; ".") ;
def replacement_index: .yamlPath | sub("^k8s-helm-templates\\.deployment\\.containers\\."; "") ;
def replace($placeholders):
  [
    JOIN(INDEX(.[]; replacement_index); $placeholders[]; placeholder_index) |
    {newvalue: .[0].value, yamlPath: .[1].yamlPath}
  ]
;

$replacements | fromjson as $replacements |
$placeholders | fromjson as $placeholders |
$replacements | .[0].replacements |= replace($placeholders)
'

この目標を達成するために、私が作成したプロトタイプを示すことでこれを説明できます。

各入力がファイルにあるとします。

cat > replacements.json <<"EOF"
[
  {
    "replacements": [
      {
        "newValue": "0",
        "yamlPath": "k8s-helm-templates.deployment.containers.abc.image.tag"
      },
      {
        "newValue": "0",
        "yamlPath": "k8s-helm-templates.deployment.containers.def.image.tag"
      },
      {
        "newValue": "0",
        "yamlPath": "k8s-helm-templates.deployment.containers.ghi.image.tag"
      }
    ],
    "yamlFilePath": "k8s/helm/Dev/us-east-1/values.yaml"
  }
]
EOF

cat > placeholders.json <<"EOF"
[
  {"name":"abc-image-tag","value":"123"},
  {"name":"def-image-tag","value":"456"}
]
EOF

最初の秘密は、各入力のハンドルを取得することです。入力が1つしかない場合、通常は標準入力からそれを読み込み、.パイプの先頭で参照します。複数の入力がある場合は、--rawfile各JSONテキストを名前付き変数にロードするために使用できます。明らかな「デフォルト」入力がない場合は、--null-inputjqを使用して標準入力から読み取ることができません。

--rawfile文字列を読み取るので、それを使用してfromjsonJSONオブジェクトを解析する必要があります。を使用してJSONオブジェクトの配列を読み取ることもできますが、--slurpfile最初の要素を選択する必要があるため、それでも追加の手順です。

jq \
--null-input \
--rawfile replacements replacements.json \
--rawfile placeholders placeholders.json \
'
$replacements | fromjson as $replacements |
$placeholders | fromjson as $placeholders |
$replacements, $placeholders
'

必要な結果は、2つのSQLデータベーステーブル間の内部結合のように見えます。 jqには、同様のことを行うことができる「SQLスタイル演算子」があるので、こう言うのです。文書化がうまくいかなかったので、ここで試行錯誤を経て調べました。

INDEX入力ストリームの各オブジェクトをキーにマッピングし、両方のインデックスJOINに対して内部結合を実行するオブジェクトを作成するために使用されます。

インデックスは$replacementsこんな感じです。ここのキー式は共通のプレフィックスを削除し、yamlPath変更可能なイメージタグを残します。

jq \
--null-input \
--rawfile replacements replacements.json \
--rawfile placeholders placeholders.json \
'
$replacements | fromjson as $replacements |
$placeholders | fromjson as $placeholders |
INDEX(
  $replacements[0].replacements[];
  .yamlPath | sub("^k8s-helm-templates\\.deployment\\.containers\\."; "")
)
'
{
  "abc.image.tag": {
    "newValue": "0",
    "yamlPath": "k8s-helm-templates.deployment.containers.abc.image.tag"
  },
  "def.image.tag": {
    "newValue": "0",
    "yamlPath": "k8s-helm-templates.deployment.containers.def.image.tag"
  },
  "ghi.image.tag": {
    "newValue": "0",
    "yamlPath": "k8s-helm-templates.deployment.containers.ghi.image.tag"
  }
}

インデックスは$placeholdersこんな感じです。キー式は、可変イメージラベルがラベルのように見えるようにダッシュをドットに置き換えます$replacements

jq \
--null-input \
--rawfile replacements replacements.json \
--rawfile placeholders placeholders.json \
'
$replacements | fromjson as $replacements |
$placeholders | fromjson as $placeholders |
INDEX($placeholders[]; .name | gsub("-"; "."))
'
{
  "abc.image.tag": {
    "name": "abc-image-tag",
    "value": "123"
  },
  "def.image.tag": {
    "name": "def-image-tag",
    "value": "456"
  }
}

2つのインデックスオブジェクトの一部のキーが一致することがわかります。これが私たちがJOINこれらのオブジェクトの内部接続を実行する機能を取得する方法です。

実際、この関数はとにかく2番目のインデックスを効果的に生成するので、一度だけINDEX呼び出すだけです。JOIN

JOIN最初のオブジェクトはストリーム入力から取得され、2 番目のオブジェクトはインデックス入力から取得されるペアリストのストリームを返します。

jq \
--null-input \
--rawfile replacements replacements.json \
--rawfile placeholders placeholders.json \
'
$replacements | fromjson as $replacements |
$placeholders | fromjson as $placeholders |
JOIN(
    INDEX(
        $replacements[0].replacements[];
        .yamlPath | sub("^k8s-helm-templates\\.deployment\\.containers\\."; "")
    );
    $placeholders[];
    .name | gsub("-"; ".")
)
'
[
  {
    "name": "abc-image-tag",
    "value": "123"
  },
  {
    "newValue": "0",
    "yamlPath": "k8s-helm-templates.deployment.containers.abc.image.tag"
  }
]
[
  {
    "name": "def-image-tag",
    "value": "456"
  },
  {
    "newValue": "0",
    "yamlPath": "k8s-helm-templates.deployment.containers.def.image.tag"
  }
]

次のステップは、関連付けられた各オブジェクトの正しいプロパティを「選択」して新しいオブジェクトを作成し、出力を配列にラップする新しいオブジェクトを作成することJOINです。

jq \
--null-input \
--rawfile replacements replacements.json \
--rawfile placeholders placeholders.json \
'
$replacements | fromjson as $replacements |
$placeholders | fromjson as $placeholders |
[
  JOIN(
    INDEX(
      $replacements[0].replacements[];
      .yamlPath | sub("^k8s-helm-templates\\.deployment\\.containers\\."; "")
    );
    $placeholders[];
    .name | gsub("-"; ".")
  ) |
  {newvalue: .[0].value, yamlPath: .[1].yamlPath}
]
'
[
  {
    "newvalue": "123",
    "yamlPath": "k8s-helm-templates.deployment.containers.abc.image.tag"
  },
  {
    "newvalue": "456",
    "yamlPath": "k8s-helm-templates.deployment.containers.def.image.tag"
  }
]

最終的な解決策では、各式の名前を指定するいくつかの関数を定義しました。更新割り当て演算子を使用して|=元の構造をコピーし$replacements、結合の結果として内部リストを更新します。

おすすめ記事