
Digamos que tengo el siguiente archivo JSON:
[
{
"name1": "fruits",
"name2": "cars",
"name3": "houses"
}
]
Sé que puedo usarlo jq
para 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 key
en 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 jq
comando no funciona en este JSON. ¿Hay alguna forma de cambiar todas name1
las 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 jq
manual (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 newname1
clave al final de cada objeto en lugar de reemplazarla name1
en la posición donde se encontró (si eso importa).
Otro enfoque (con jq
1.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