É possível alterar recursivamente os nomes das chaves com jq usando o método with_entries?

É possível alterar recursivamente os nomes das chaves com jq usando o método with_entries?

Digamos que eu tenha o seguinte arquivo JSON:

[
  {
    "name1": "fruits",
    "name2": "cars",
    "name3": "houses"
  }
]

Eu sei que posso usar jqpara renomear seus valores como o seguinte:

jq '[.[] | .["newname1"] = .name1 | del(.name1)]' file

Isso funciona bem e me permite fazer alterações mesmo em estruturas JSON mais complexas... No entanto, essa é uma declaração muito explícita das chaves que desejo alterar. Uma maneira alternativa de fazer a mesma coisa seria com o comando:

jq 'map(with_entries(if .key == "name1" then .key = "newname1" else . end))' file 

Esta é uma forma de verificar todas as chaves com nomes específicos dentro de um JSON que é um Array de Objetos e alterá-las. Não preciso declarar explicitamente o nome do keyneste caso. No entanto, isso funciona apenas em uma matriz de objetos. Eu gostaria de encontrar uma maneira de alterar todas as chaves dentro de um JSON assim de forma recursiva. Digamos que eu tenha um JSON como este:

{
  "name1": "one",
  "type": "FeatureCollection",
  "features": [
    {
      "name1": "one",
      "valueA": "0",
      "valueB": "0",
      "keyB": "2",
      "keyC": "3"
    },
    {
      "name1": "two",
      "valueA": "11",
      "valueB": "21",
      "keyB": "15",
      "keyC": "20"
    }
  ]
}

Meu último jqcomando não funciona neste JSON. Existe alguma maneira de alterar todas name1as chaves recursivamente usando jq? Talvez encontrando uma maneira de usar recurse(.[]?;true)junto com este comando? É possível?

Responder1

jq 'walk(if type == "object" then with_entries( if .key == "name1" then .key = "newname1" else . end ) else . end)' file

Isso vem mais ou menos direto do jqmanual (a seção que descreve a walk()função). A walk()função atua como uma "recursiva map()" e a única coisa que precisamos ter cuidado é verificar o tipo de entidade com a qual estamos lidando atualmente.

Usando walk(), você também pode aplicar a sua primeira abordagem:

jq 'walk(if type == "object" and has("name1") then ( .newname1 = .name1 | del(.name1) ) else . end)' file

No entanto, isso coloca a newname1chave por último em cada objeto, em vez de substituí-la name1na posição onde foi encontrada (se isso for importante).

Outra abordagem (com jq1.6) é usar o operador decente recursivo .., selecionando qualquer coisa que tenha a chave que procuramos e, em seguida, atualizando esses objetos:

jq '(.. | select(has("name1")?)) |= with_entries(if .key == "name1" then .key = "newname1" else . end)' file

informação relacionada