Tracks
/
jq
jq
/
Temario
/
Objetos
Ob

Objetos en jq

4 ejercicios

Acerca de Objetos

Un objeto JSON es, usando la terminología de otros lenguajes, un «hash», un «map» o un «dictionary».

JSON define un objeto así:

Un objeto es un conjunto no ordenado de pares nombre/valor. Un objeto empieza con { (llave izquierda) y termina con } (llave derecha). Cada nombre va seguido de : (dos puntos) y los pares nombre/valor se separan con , (coma).

El nombre debe ser un string. Otra palabra para nombre es clave.

El valor puede ser de cualquier tipo JSON. Distintos valores del mismo objeto pueden ser de tipos diferentes, como en este ejemplo.

{
  "name": "Jane",
  "age": 42,
  "pets": ["cat", "fish"],
  "address": {"street": "123 Main St", "city": "Springfield"}
}

Ten en cuenta que no debe haber una coma después del último par clave-valor.

Crear objetos

Usa llaves para agrupar los pares nombre/valor. Aunque los nombres deben ser strings, no hace falta entrecomillarlos si son similares a un identificador (formados por caracteres alfanuméricos y guion bajo, y que no empiezan por un dígito).

{name: "Jane", age: 42}

Es válido usar claves que no sean similares a un identificador. Solo hay que entrecomillarlas.

{"first name": "Jane", "last name": "Lopez", age: 42}

Si el nombre es el resultado de una expresión, esta debe ir entre paréntesis.

$ echo "Jane" | jq -Rc '{.: 42}'
jq: error: syntax error, unexpected '.' (Unix shell quoting issues?) at <top-level>, line 1:
{.: 42}
jq: error: May need parentheses around object key expression at <top-level>, line 1:
{.: 42}
jq: 2 compile errors

$ echo "Jane" | jq -Rc '{(.): 42}'
{"Jane":42}

Notaciones abreviadas

Un par de casos frecuentes al construir objetos tienen una sintaxis abreviada.

  1. Reutilizar pares clave-valor de un objeto de entrada.

    $ jq -n '$ENV | {USER: .USER, EDITOR: .EDITOR}'
    {
      "USER": "glennj",
      "EDITOR": "vim"
    }
    

    $ENV es un objeto que contiene los pares nombre-valor del entorno.

    Los repetitivos pares key: .key se pueden escribir simplemente como key

    $ jq -n '$ENV | {USER, EDITOR}'
    {
      "USER": "glennj",
      "EDITOR": "vim"
    }
    
  2. De forma similar, hay una abreviatura cuando se usan variables.

    $ jq -cn '"foo" as $a | "bar" as $b | {a: $a, b: $b}'
    {"a":"foo","b":"bar"}
    
    $ jq -cn '"foo" as $a | "bar" as $b | {$a, $b}'
    {"a":"foo","b":"bar"}
    

Indexación

Los valores se obtienen de un objeto con la notación de punto.

{name: "Jane", age: 42} | .age    # => 42

Si no puedes referirte a la clave como un identificador, usa la notación de corchetes.

"name" as $key | {name: "Jane", age: 42} | .$key    # => error
"name" as $key | {name: "Jane", age: 42} | .[$key]  # => "Jane"

Si la clave no está en el objeto, el resultado es null.

{name: "Jane", age: 42} | .sport  # => null

Indexar valores anidados

Descubrirás que esta es una acción que tendrás que hacer una y otra vez cuando procesas los resultados de consultas a una API.

Dado un objeto que contiene valores de tipo array u objeto, podemos «encadenar» expresiones de índice.

{
  "name": "Jane",
  "age": 42,
  "pets": ["cat", "fish"],
  "address": {"street": "123 Main St", "city": "Springfield"}
}
| (
  .pets[1],       # => "fish"
  .address.city   # => "Springfield"
)

Añadir o cambiar pares clave-valor

Para añadir un nuevo par clave-valor a un array, o para actualizar el valor de una clave existente, usa el operador de asignación =, con una expresión de índice en el lado izquierdo.

{name: "Jane", age: 42} | .sport = "tennis" | .age = 21
# => {
#      "name": "Jane",
#      "age": 21,
#      "sport": "tennis"
#    }

El operador + fusiona objetos.

{Richard: 54} + {Jane: 42}
# => {
#      "Richard": 54,
#      "Jane": 42
#    }

Eliminar una clave

Usa la función del para eliminar una clave. Devuelve el objeto actualizado.

{name: "Jane", age: 42} | del(.age)   # => {"name": "Jane"}

El parámetro de del es una expresión de índice (con notación de punto o de corchetes) que se resuelve en una clave del objeto. jq la llama expresión de ruta. No basta con dar simplemente un string.

{name: "Jane", age: 42} | del(name)        # error: name/0 is not defined
{name: "Jane", age: 42} | del("name")      # error: Invalid path expression with result "name"
{name: "Jane", age: 42} | del(.name)       # OK
{name: "Jane", age: 42} | del(.["name"])   # OK

Pertenencia

  • Para comprobar si el objeto tiene una clave, usa la función has.

    {name: "Jane", age: 42} as $example
    |
      ($example | has("name")),    # => true
      ($example | has("sport"))    # => false
    
  • Comprueba si una clave está en un objeto con in.

    {name: "Jane", age: 42} as $example
    |
      ("name"  | in($example)),    # => true
      ("sport" | in($example))     # => false
    

Listar las claves o los valores

Usa la función keys para generar un array con todas las claves.

{name: "Jane", age: 42} | keys   # => ["age", "name"]

Ten en cuenta que keys ordena las claves. Para obtener las claves en el orden original, usa keys_unsorted.

No hay ninguna función equivalente para listar todos los valores. Sin embargo, el filtro .[] genera los valores del objeto como un flujo, y ese flujo se puede capturar con el constructor de arrays [...].

[{first: "Jane", last: "Lopez", status: "awesome!"} | .[]]
# => ["Jane", "Lopez", "awesome!"]

Iteración

  • La función map_values(filter) aplica el filtro a cada valor del objeto.

    {first: "Jane", last: "Lopez", status: "awesome!"}
    | map_values(ascii_upcase)
    # => {"first": "JANE", "last": "LOPEZ", "status": "AWESOME!"}
    
  • Para iterar sobre un objeto, primero tenemos que convertirlo en un array de objetos clave-valor. La función to_entries hace eso.

    {name: "Jane", age: 42} | to_entries
    # => [
    #      {
    #        "key": "name",
    #        "value": "Jane"
    #      },
    #      {
    #        "key": "age",
    #        "value": 42
    #      }
    #    ]
    

    En este punto, podemos usar funciones de iteración de arrays, como map.

  • La función from_entries es la inversa: convierte un array de objetos clave-valor en un objeto.

    [
      {"key":"name", "value":"Jane"},
      {"key":"age", "value":42}
    ] | from_entries                  # => {"name": "Jane", "age": 42}
    
  • Para aplicar un filtro a cada par clave-valor de un objeto, usa la función with_entries(filter).

    Por ejemplo, dado un objeto que asocia un nombre a una edad, las claves y los valores se pueden intercambiar así.

    {"Jane": 42, "Richard": 54}
    | with_entries({key: (.value | tostring), value: .key})
    

    genera

    {
      "42": "Jane",
      "54": "Richard"
    }
    

    with_entries(filter) es lo mismo que

    to_entries | map(filter) | from_entries
    
Editar en GitHub El enlace se abre en una nueva ventana o pestaña

Aprende Objetos

La práctica está bloqueada

Desbloquea 4 ejercicios más para practicar Objetos