필드 검색 및 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"}
]

당신이 얻어야 할 것은 주어진 값이 올바르게 대체되고 0 값이 다음과 같이 필터링된다는 것입니다.

[
  {
    "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

첫 번째 비결은 각 입력에 대한 핸들을 얻는 것입니다. 입력이 하나만 있는 경우 일반적으로 표준 입력에서 이를 읽고 .파이프 시작 부분에서 참조합니다. 입력이 여러 개인 경우 --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
'

원하는 결과는 두 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이렇게 생겼습니다. 키 표현식은 가변 이미지 레이블이 labels 처럼 보이도록 대시를 점으로 바꿉니다 $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"
  }
}

두 인덱스 개체의 일부 키가 일치하는 것을 볼 수 있습니다. 이것이 우리가 JOIN이러한 객체의 내부 연결을 수행하는 기능을 얻는 방법입니다.

실제로 이 함수는 어쨌든 두 번째 인덱스를 효과적으로 생성하므로 INDEX한 번만 호출하면 됩니다 .JOIN

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("-"; ".")
)
'
[
  {
    "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하고 조인 결과로 내부 목록을 업데이트합니다.

관련 정보