Asumiremos que ya conoces la sintaxis de JSON y sus tipos de datos.
jq funciona pasando los datos JSON de entrada por una única expresión (escrita como una tubería de filtros) para obtener los datos transformados que deseas.
El lenguaje jq está implementado por el programa jq.
Este programa ofrece varias opciones de línea de comandos muy útiles para controlar cómo se consume la entrada y cómo se presenta la salida.
En los ejemplos siguientes encontrarás:
-n o --null-input
Normalmente al programa jq se le da un fichero que leer, o bien le envías datos a su entrada.
La opción --null-input te permite generar datos JSON sin ninguna entrada.
-c o --compact-output
Por defecto, jq presenta su salida de forma legible.
Para las personas es muy útil ver los datos cuando están bien formateados.
Sin embargo, eso no es necesario para las máquinas: la opción --compact-output elimina los espacios en blanco del formato para minimizar el tamaño del JSON resultante.
-f filename o --from-file filename
Lee el programa jq desde filename en lugar de proporcionarlo en la línea de comandos.
Tanto sed como awk usan la opción -f con el mismo propósito.
Verás que se usa en los scripts de pruebas de los ejercicios de práctica.
El resto de esta lección se centrará en el lenguaje jq.
Los filtros también se conocen como expresiones.
Un filtro recibe una entrada y produce una salida.
Igual que cuando trabajas en un shell de Unix, puedes unir filtros con una tubería | para conectar la salida de un filtro con la entrada de otro.
.
Este es el filtro más sencillo. Simplemente pasa su entrada a su salida.
$ echo '[1, 2, 3]' | jq '.'
[
1,
2,
3
]
Esta será una introducción rápida al trabajo con arrays. Cubriremos este tema con más detalle más adelante.
Se accede a los elementos del array con corchetes, y su índice empieza en cero.
$ echo '[10, 20, 30]' | jq '.[1]'
20
Un filtro puede construir un array envolviendo una expresión entre [ y ]
con una lista conocida de elementos:
jq -n '[1, 2, 3]'
para recopilar un flujo de elementos: por ejemplo,
range es una función que produce un flujo de números
$ jq -n 'range(10; 70; 15)'
10
25
40
55
Usar [] recopila los resultados de la expresión en un array
$ jq -c -n '[range(10; 70; 15)]'
[10,25,40,55]
La coma no es solo sintaxis que separa elementos de un array. La coma es un operador que une flujos.
Por ejemplo, [1, 2, 3] es un filtro que usa el constructor de arrays [] para recopilar el resultado de unir las tres expresiones 1, 2 y 3.
¿Te has fijado en los puntos y coma de range(10; 70; 15), más arriba?
Como las comas tienen un propósito específico en el lenguaje jq, las funciones que reciben varios argumentos usan puntos y coma para separar los argumentos.
Una introducción rápida a los objetos.
Como en muchos lenguajes de programación, se usan puntos para acceder a las propiedades de un objeto
$ echo '{"foo": {"bar": "qux"}}' | jq '.foo.bar'
"qux"
También se pueden usar corchetes con los objetos, pero entonces hacen falta comillas para los literales de string. Este es un método para trabajar con claves que contienen espacios.
$ echo '{"foo bar": "qux"}' | jq '.["foo bar"]'
"qux"
Puedes construir un objeto con {} y pares key: value.
No hacen falta comillas alrededor de las claves que son strings «simples».
jq -n '{question: (6 * 9), answer: 42}'
produce
{
"question": 54,
"answer": 42
}
Para tratar la clave como una expresión, debes envolverla entre paréntesis (lo siguiente también produce lo mismo que el ejemplo anterior).
echo '[{"key":"question", "value":54}, {"key":"answer", "value":42}]' \
| jq '{(.[0].key): .[0].value, (.[1].key): .[1].value}'
Por ejemplo, dado file.json con el siguiente contenido
{
"key1": "value1",
"key2": [5, 15, 25]
}
Vamos a calcular la longitud del array key2:
$ jq '.key2 | length' file.json
3
Estamos pasando por una tubería la salida de la expresión .key2 como entrada de length, que, como era de esperar, produce el número de elementos del array.
En este ejemplo, los datos JSON de entrada se ignoran y no influyen en la salida:
$ echo '{"answer": 42}' | jq '6 * 9'
54
Un filtro puede producir más de un valor.
Por ejemplo, el filtro .[] produce cada elemento de un array como un valor independiente:
$ jq -n -c '[1, 2, 3]'
[1,2,3]
$ jq -n -c '[1, 2, 3] | .[]'
1
2
3
Si conectas un filtro así a otro mediante una tubería, se ejecutará el segundo filtro para cada valor:
$ jq -n -c '[1, 2, 3] | .[] | . * 2'
2
4
6
Esto es como una iteración implícita.
Cuando entiendas esta técnica, te darás cuenta de que los filtros jq más potentes pueden ser muy concisos.
Los paréntesis se usan para agrupar subexpresiones y forzar el orden de las operaciones, igual que en otros lenguajes.
En jq, puede resultar algo sorprendente que hagan falta.
Por ejemplo, supongamos que queremos construir un array con 2 elementos: la raíz cuadrada de 9; y e elevado a la potencia 1.
Las dos expresiones individuales son 9 | sqrt y 1 | exp.
Esperamos que la salida sea el array [3, 2.7...]
$ jq -n '[ 9|sqrt, 1|exp ]'
[
20.085536923187668,
2.718281828459045
]
¿Por qué no obtuvimos lo que esperábamos? jq lo interpreta así:
[ ((9|sqrt), 1) | exp ]
jq construye un flujo de dos elementos (3 y 1) que se pasan cada uno a exp.
Necesitamos asegurarnos de que exp solo reciba un número como entrada.
En otras palabras, debemos forzar que la tubería se evalúe antes que la coma.
$ jq -n '[ 9|sqrt, (1|exp) ]'
[
3,
2.718281828459045
]
Sin entrar en demasiada profundidad (las funciones serán el tema de otro ejercicio), aquí tienes algunas funciones integradas útiles:
length
Dado un array como entrada, produce el número de elementos del array.
$ jq -n '[10, 20, 30, 40] | length'
4
+
Este operador hace cosas distintas según el tipo de sus operandos: suma números, concatena strings, añade arrays, fusiona objetos.
$ jq -c -n '
3 + 4,
"foo" + "bar",
["a", "b"] + ["c"],
{"m": 10} + {"n": 20}
'
7
"foobar"
["a","b","c"]
{"m":10,"n":20}
add es una función que recibe un array y devuelve un elemento con todos los elementos sumados entre sí según las reglas de +.
[1, 2, 3] | add produce 6.
map
Dado un array como entrada y un filtro como argumento, produce un array en el que el filtro se aplica a cada elemento
$ jq -c -n '[10, 20, 30, 40] | map(. / 5)'
[2,4,6,8]
select
Dada alguna entrada y un filtro como argumento:
null, sino realmente ninguna salida)Por ejemplo, dados algunos números, selecciona los que son divisibles por 3
$ jq -n 'range(10) | select(. % 3 == 0)'
0
3
6
9
Recuerda que range produce un flujo de números.
select se invocará una vez por cada número.
Solo se producen los números que «pasan» la expresión.
A menudo necesitas seleccionar elementos de un array. Hay un par de formas de hacerlo.
Dada la entrada ["Anne", "Bob", "Cathy", "Dave"], selecciona los nombres que tienen longitud 4.
usar map y select juntos
map(select(length == 4))
descomponer el array en elementos, aplicar select a ese flujo y recopilar los resultados
[ .[] | select(length == 4) ]
Los comentarios empiezan con el carácter # y continúan hasta el final de la línea.
De repente te ha entrado un antojo de tortitas. Como persona moderna con inclinaciones técnicas, escribes una lista de la compra con los ingredientes de las tortitas en formato JSON. La estructura de la lista es:
{
"name": "name of shopping list",
"ingredients": [ ...list of ingredients... ],
"optional ingredients": [ ...list of ingredients... ]
}
Un ingrediente se representa como un objeto JSON, así:
{
"item": "flour",
"amount": {
"quantity": 2,
"unit": "cup"
}
}
Un ingrediente tiene una propiedad opcional llamada "substitute" que contiene un string con otro ingrediente que se puede usar en su lugar.
Vamos a ver cómo podemos examinar la lista de la compra con jq.
Escribe una expresión que devuelva el elemento "name" de la lista de la compra.
Cuenta solo los ingredientes «obligatorios». No incluyas los ingredientes opcionales.
Escribe una expresión que devuelva la cantidad de azúcar. Solo se quiere la parte numérica.
Algunos ingredientes se pueden sustituir (si no tienes el ingrediente X puedes usar Y). Genera un objeto JSON que asocie el ingrediente recomendado con su sustituto. Incluye los ingredientes opcionales en esa correspondencia.
Regístrate en Exercism para aprender y dominar jq con 12 conceptos75 ejercicios y mentoría humana real, todo gratis.