¿Es posible cambiar recursivamente los nombres de las claves con jq usando el método with_entries?

¿Es posible cambiar recursivamente los nombres de las claves con jq usando el método with_entries?

Digamos que tengo el siguiente archivo JSON:

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

Sé que puedo usarlo jqpara cambiar el nombre de sus valores de la siguiente manera:

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

Esto funciona bien y me permite hacer cambios incluso en estructuras JSON más complejas... Sin embargo, esa es una declaración muy explícita de las claves que quiero cambiar. Una forma alternativa de hacer lo mismo sería con el comando:

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

Esta es una forma de verificar todas las claves con nombres específicos dentro de un JSON que es una matriz de objetos y cambiarlas. No necesito declarar explícitamente el nombre de keyen este caso. Sin embargo, esto sólo funciona en una matriz de objetos. Me gustaría encontrar una manera de cambiar todas las claves dentro de un json como ese de forma recursiva. Digamos que tengo un JSON como el siguiente:

{
  "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"
    }
  ]
}

Mi último jqcomando no funciona en este JSON. ¿Hay alguna forma de cambiar todas name1las claves de forma recursiva jq? ¿Quizás encontrar una manera de usarlo recurse(.[]?;true)junto con este comando? ¿Es posible?

Respuesta1

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

Esto proviene más o menos directamente del jqmanual (la sección que describe la walk()función). La walk()función actúa como "recursiva map()" y lo único con lo que debemos tener cuidado es verificar el tipo de entidad con la que estamos tratando actualmente.

Usando walk(), también puedes aplicar tu primer enfoque:

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

Sin embargo, esto coloca la newname1clave al final de cada objeto en lugar de reemplazarla name1en la posición donde se encontró (si eso importa).

Otro enfoque (con jq1.6) es usar el operador recursivo decente .., seleccionar cualquier cosa que tenga la clave que estamos buscando y luego actualizar esos objetos:

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

información relacionada