0Pricing
DevOps Bootcamp · Lección

Transformación y construcción de objetos JSON con jq

Reestructure datos con map, to_entries y la construcción de objetos para generar nuevas cargas útiles JSON.

Transformación y construcción de objetos JSON con jq es una lección gratuita de DevOps Bootcamp en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de DevOps Bootcamp, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de DevOps Bootcamp incluye 4 lecciones en total.

¿Por qué transformar JSON?

El JSON sin procesar de las API o los archivos de registro rara vez tiene exactamente la estructura que necesita. Puede recibir un objeto grande y querer solo algunos campos, o necesitar cambiar el nombre de las claves, aplanar estructuras anidadas o crear un payload completamente nuevo para enviarlo a otro servicio.

jq es un procesador de JSON ligero y potente para la línea de comandos que permite realizar estas transformaciones en una sola canalización. En esta lección aprenderá las tres técnicas fundamentales para remodelar datos:

  • Construcción de objetos — crear un objeto JSON nuevo desde cero
  • map — aplicar una transformación a cada elemento de un array
  • to_entries / from_entries — tratar los pares clave-valor de un objeto como un array para poder filtrarlos y reconstruirlos

Todos los ejemplos presuponen que jq está instalado (apt install jq / brew install jq).

Conceptos básicos de la construcción de objetos

La función más fundamental de jq es la construcción de objetos: envolver expresiones en {} para crear un objeto JSON nuevo. Puede elegir qué campos incluir y cómo denominarlos.

Sintaxis:

  • { newKey: .existingField } — cambiar el nombre de un campo
  • { name, age } — forma abreviada cuando la nueva clave coincide con el nombre del campo
  • { total: (.price * .qty) } — calcular un valor directamente

El fragmento siguiente lee un JSON de producto y produce una estructura más sencilla con un campo subtotal calculado.

#!/usr/bin/env bash
# Object construction: pick and rename fields
product='{
  "id": 42,
  "name": "Widget Pro",
  "price": 9.99,
  "qty": 3,
  "warehouse": "EU-West"
}'

echo "$product" | jq '{
  productId: .id,
  name,
  subtotal: (.price * .qty)
}'

Construcción de objetos a partir de datos anidados

El JSON del mundo real suele estar anidado. jq permite acceder a rutas anidadas dentro de un constructor de objetos y aplanar la estructura al mismo tiempo.

Use la notación de rutas con puntos dentro de la expresión del valor del constructor:

  • { city: .address.city }
  • { lat: .location.coords.lat }

El ejemplo siguiente toma un registro de usuario profundamente anidado y produce un resumen plano adecuado para una fila de encabezados CSV o el cuerpo de una solicitud a una API.

#!/usr/bin/env bash
user='{
  "id": "u-001",
  "profile": {
    "displayName": "Ada Lovelace",
    "contact": { "email": "ada@example.com", "phone": "+44-700" }
  },
  "plan": "pro"
}'

echo "$user" | jq '{
  id,
  name: .profile.displayName,
  email: .profile.contact.email,
  plan
}'

Transformación de arrays con map

map(expr) es el equivalente de jq a un for-each: aplica expr a cada elemento de un array de entrada y devuelve un array nuevo con la misma longitud.

Aspectos clave:

  • map(expr) es una forma abreviada de [.[] | expr]
  • La expresión interna puede ser cualquier filtro de jq, incluida la construcción de objetos
  • Encadénelo con select() para filtrar antes de transformar

El fragmento procesa una lista de pedidos y conserva únicamente los campos necesarios para un manifiesto de envío.

#!/usr/bin/env bash
orders='[
  {"orderId": 1, "customer": "Alice", "total": 42.50, "status": "shipped"},
  {"orderId": 2, "customer": "Bob",   "total": 18.00, "status": "pending"},
  {"orderId": 3, "customer": "Carol", "total": 99.99, "status": "shipped"}
]'

# Produce a shipping manifest: only shipped orders, slim fields
echo "$orders" | jq '[
  .[] | select(.status == "shipped") | {
    id: .orderId,
    recipient: .customer,
    amount: .total
  }
]'

map con campos calculados

Dentro de map puede calcular nuevos valores, convertir tipos y combinar campos, no solo copiarlos. Algunos patrones habituales son:

  • Interpolación de cadenas: "\(.first) \(.last)"
  • Aritmética: (.price * 1.2 | round) para aplicar un recargo del 20 %
  • Condicionales: if .score >= 90 then "A" else "B" end

El ejemplo siguiente amplía una lista de empleados añadiendo un fullName calculado y una etiqueta de seniority basada en los años de experiencia.

#!/usr/bin/env bash
staff='[
  {"first": "Grace", "last": "Hopper",  "years": 15},
  {"first": "Alan",  "last": "Turing",  "years": 4},
  {"first": "Linus", "last": "Torvalds","years": 9}
]'

echo "$staff" | jq 'map({
  fullName: "\(.first) \(.last)",
  years,
  seniority: (if .years >= 10 then "senior" elif .years >= 5 then "mid" else "junior" end)
})'

Comprender to_entries

to_entries convierte un objeto JSON en un array de pares {key, value}. Esto permite aplicar operaciones de arrays (map, select, sort) a los campos de un objeto, algo que no se puede hacer directamente sobre un objeto.

Ejemplo de transformación:

  • Entrada: {"a": 1, "b": 2}
  • Salida: [{"key": "a", "value": 1}, {"key": "b", "value": 2}]

La operación inversa es from_entries, que convierte ese array de nuevo en un objeto. Juntos forman el modismo to_entries | map(...) | from_entries para realizar transformaciones a nivel de objeto.

#!/usr/bin/env bash
# Demonstrate to_entries and from_entries
config='{"host": "db.local", "port": 5432, "ssl": true}'

echo "--- to_entries output ---"
echo "$config" | jq 'to_entries'

echo "--- round-trip back to object ---"
echo "$config" | jq 'to_entries | from_entries'

Filtrar claves con to_entries

Uno de los usos más prácticos de to_entries es filtrar dinámicamente las claves que se conservan o se descartan según el propio nombre de la clave, algo que la construcción de objetos no puede hacer cuando se desconocen de antemano los nombres de las claves.

Patrón:

  • to_entries | map(select(.key | test("regex"))) | from_entries
  • to_entries | map(select(.key != "secret")) | from_entries

El fragmento siguiente elimina todas las claves que comienzan por un guion bajo (campos internos o privados) antes de reenviar un objeto de configuración a un servicio externo.

#!/usr/bin/env bash
raw_config='{
  "endpoint": "https://api.example.com",
  "timeout": 30,
  "_internalToken": "s3cr3t",
  "_debugMode": true,
  "retries": 3
}'

# Remove any key starting with underscore
echo "$raw_config" | jq '
  to_entries
  | map(select(.key | startswith("_") | not))
  | from_entries
'

Cambiar nombres de claves dinámicamente con to_entries

La construcción de objetos permite cambiar el nombre de las claves cuando conoce sus nombres al escribir el código. to_entries permite cambiar el nombre de las claves mediante programación, por ejemplo, convertir camelCase en snake_case o añadir un prefijo.

Dentro de map actualiza el campo .key de cada entrada y, después, utiliza una tubería hacia from_entries:

  • map(.key |= gsub("(?<=[a-z])(?=[A-Z])"; "_") | .key |= ascii_downcase) — convertir camelCase en snake_case
  • map(.key |= "app_" + .) — añadir un prefijo a cada clave

El ejemplo añade el prefijo APP_ a todos los nombres de variables de entorno para asignarles un espacio de nombres antes de inyectarlas en un contenedor.

#!/usr/bin/env bash
env_vars='{"host": "localhost", "port": "8080", "debug": "false"}'

# Add APP_ prefix and uppercase all keys
echo "$env_vars" | jq '
  to_entries
  | map({ key: ("APP_" + (.key | ascii_upcase)), value })
  | from_entries
'

with_entries: la forma abreviada conveniente

El patrón to_entries | map(...) | from_entries es tan habitual que jq proporciona una forma abreviada: with_entries(expr).

Es exactamente equivalente, pero más conciso:

  • with_entries(.value |= . * 2) — duplicar cada valor numérico
  • with_entries(select(.value != null)) — eliminar las claves cuyos valores sean nulos
  • with_entries(.key |= ascii_upcase) — convertir todas las claves a mayúsculas

El fragmento elimina todas las claves cuyo valor sea null o una cadena vacía, un paso habitual de limpieza antes de enviar una solicitud PATCH a una API REST.

#!/usr/bin/env bash
patch_body='{
  "name": "Mehmet",
  "email": "",
  "phone": null,
  "city": "Istanbul"
}'

# Drop empty/null fields before PATCH
cleaned=$(echo "$patch_body" | jq '
  with_entries(select(.value != null and .value != ""))
')

echo "Cleaned payload:"
echo "$cleaned"

# In practice you would pipe to curl:
# curl -s -X PATCH https://api.example.com/users/1 \
#   -H "Content-Type: application/json" \
#   -d "$cleaned"

Combinar map y la construcción de objetos en una canalización

Las transformaciones reales encadenan varias operaciones de jq. Una canalización habitual para preparar un payload de API podría:

  1. Filtrar el array de entrada con map(select(...))
  2. Remodelar cada elemento mediante la construcción de objetos
  3. Añadir campos calculados
  4. Ordenar el resultado

El ejemplo siguiente lee una lista de métricas de servidores, conserva solo los servidores con un uso elevado de CPU y produce un payload compacto de alerta listo para enviarse mediante POST a un webhook.

#!/usr/bin/env bash
metrics='[
  {"host": "web-01", "cpu": 23, "mem": 60, "region": "eu"},
  {"host": "web-02", "cpu": 91, "mem": 88, "region": "eu"},
  {"host": "db-01",  "cpu": 78, "mem": 95, "region": "us"},
  {"host": "db-02",  "cpu": 12, "mem": 40, "region": "us"}
]'

alerts=$(echo "$metrics" | jq '[
  .[] | select(.cpu > 75 or .mem > 85) | {
    server: .host,
    region,
    severity: (if .cpu > 90 or .mem > 90 then "critical" else "warning" end),
    metrics: { cpu: .cpu, mem: .mem }
  }
] | sort_by(.severity)')

echo "$alerts"

Crear un objeto JSON nuevo a partir de varias fuentes

jq puede combinar entradas y construir objetos a partir de varias fuentes JSON mediante el operador de suma + y la asignación de variables con as $var.

Patrones útiles:

  • obj1 + obj2 — combinar dos objetos (el de la derecha prevalece si hay claves en conflicto)
  • --argjson — pasar un segundo documento JSON como variable
  • $ENV — leer variables de entorno directamente dentro de jq

El fragmento combina una configuración base con anulaciones específicas del entorno, un patrón habitual para gestionar la configuración de aplicaciones de 12 factores en scripts de shell.

#!/usr/bin/env bash
base_config='{
  "logLevel": "info",
  "timeout": 30,
  "retries": 3,
  "database": "postgres://db.local/app"
}'

env_overrides='{
  "logLevel": "debug",
  "database": "postgres://db.staging/app_staging"
}'

# Merge: overrides win on conflicts
merged=$(echo "$base_config" | jq --argjson overrides "$env_overrides" '. + $overrides')

echo "Merged config:"
echo "$merged"

Comprobación de conocimientos: to_entries frente a map

Tiene el siguiente objeto JSON y necesita eliminar todas las claves cuyo valor sea menor que 0, produciendo un objeto nuevo que contenga únicamente valores no negativos. ¿Qué expresión de jq lo consigue correctamente?

Entrada: {"a": 10, "b": -3, "c": 0, "d": 5}

Resumen de la lección: transformar JSON con jq

Ha estudiado las técnicas esenciales para remodelar JSON con jq:

  • Construcción de objetos {} — crear objetos nuevos seleccionando, cambiando el nombre y calculando campos a partir de una entrada
  • map(expr) — aplicar cualquier transformación a cada elemento de un array, incluida la construcción de objetos anidados y select() para filtrar
  • to_entries / from_entries — convertir un objeto en un array de pares {key, value}, lo que permite operar sobre claves y valores como en un array, y después volver a convertirlo
  • with_entries(expr) — forma abreviada y concisa de la canalización completa to_entries → map → from_entries
  • Combinar objetos con + y --argjson para payloads de varias fuentes

Estos elementos se pueden combinar: filtre con select, remodele con la construcción de objetos, amplíe con campos calculados y encadénelo todo en una única expresión de jq legible. Dominar estos patrones le permite manipular prácticamente cualquier payload JSON directamente en el shell, sin escribir un script específico en Python o Node.

Preguntas frecuentes

¿La lección «Transformación y construcción de objetos JSON con jq» es gratis?

Sí — el texto completo de «Transformación y construcción de objetos JSON con jq» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de DevOps Bootcamp, actualiza a CoddyKit PRO. El curso de DevOps Bootcamp incluye 4 lecciones en total.

¿Qué aprenderé en «Transformación y construcción de objetos JSON con jq»?

Reestructure datos con map, to_entries y la construcción de objetos para generar nuevas cargas útiles JSON. Practicas DevOps Bootcamp con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar DevOps Bootcamp?

No se requiere experiencia previa. DevOps Bootcamp en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.

¿Cuánto tiempo toma la lección «Transformación y construcción de objetos JSON con jq»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de DevOps Bootcamp?

Sí. Cada lección de DevOps Bootcamp incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Filtrado y selección de JSON con pipelines de jq
  2. Transformación y construcción de objetos JSON con jq
  3. Consumo conjunto de API REST con curl y jq
  4. Edición de archivos de configuración YAML con yq
← Volver a DevOps Bootcamp