Trilhas
/
jq
jq
/
Programa
/
Objetos
Ob

Objetos em jq

4 exercícios

Sobre Objetos

Um objeto JSON é, para usar a terminologia de outras linguagens, um "hash", um "map" ou um "dicionário".

O JSON define um objeto assim:

Um objeto é um conjunto não ordenado de pares nome/valor. Um objeto começa com { chave de abertura e termina com } chave de fechamento. Cada nome é seguido por : dois-pontos, e os pares nome/valor são separados por , vírgula.

O nome precisa ser uma string. Outra palavra para nome é chave.

O valor pode ser de qualquer tipo do JSON. Valores diferentes dentro do mesmo objeto podem ser de tipos diferentes, como neste exemplo.

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

Repare que não pode haver uma vírgula depois do último par chave-valor.

Criar objetos

Use chaves para agrupar os pares nome/valor. Embora os nomes precisem ser strings, eles não precisam estar entre aspas se forem semelhantes a um identificador (compostos de caracteres alfanuméricos e sublinhado, e que não comecem com um dígito).

{name: "Jane", age: 42}

É válido usar chaves que não sejam semelhantes a um identificador. Basta colocá-las entre aspas.

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

Se o nome for o resultado de uma expressão, a expressão precisa estar entre parênteses.

$ 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}

Notações abreviadas

Alguns casos frequentes de construção de objetos têm uma sintaxe abreviada.

  1. Reutilizar pares chave-valor de um objeto de entrada.

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

    $ENV é um objeto que contém os pares nome-valor do ambiente.

    Os pares repetitivos key: .key podem ser escritos apenas como key

    $ jq -n '$ENV | {USER, EDITOR}'
    {
      "USER": "glennj",
      "EDITOR": "vim"
    }
    
  2. Da mesma forma, existe uma forma abreviada quando se usam variáveis.

    $ 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"}
    

Indexação

Os valores são obtidos de um objeto com notação de ponto.

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

Se você não puder se referir à chave como um identificador, use notação de colchetes.

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

Se a chave não estiver no objeto, o resultado é null.

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

Indexação de valores aninhados

Você vai descobrir que essa é uma ação que precisa fazer de novo e de novo ao processar resultados de consultas a APIs.

Dado um objeto que contém valores de array ou de objeto, podemos "encadear" expressões de índice.

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

Adicionar ou alterar pares chave-valor

Para adicionar um novo par chave-valor a um array, ou para atualizar o valor de uma chave existente, use o operador de atribuição =, com uma expressão de índice do lado esquerdo.

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

O operador + vai mesclar objetos.

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

Remover uma chave

Use a função del para remover uma chave. Ela retorna o objeto atualizado.

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

O parâmetro de del é uma expressão de índice (usando notação de ponto ou de colchetes) que resolve para uma chave do objeto. O jq chama isso de expressão de caminho. Não basta passar apenas uma 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

Pertencimento

  • Para testar se o objeto tem uma chave, use a função has.

    {name: "Jane", age: 42} as $example
    |
      ($example | has("name")),    # => true
      ($example | has("sport"))    # => false
    
  • Teste se uma chave está em um objeto com in.

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

Listar as chaves ou os valores

Use a função keys para gerar uma lista com todas as chaves.

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

Repare que keys vai ordenar as chaves. Para obter as chaves na ordem original, use keys_unsorted.

Não existe uma função equivalente para listar todos os valores. No entanto, o filtro .[] produz os valores do objeto como um stream, e esse stream pode ser capturado com o construtor de array [...].

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

Iteração

  • A função map_values(filter) aplica o filtro a cada valor do objeto.

    {first: "Jane", last: "Lopez", status: "awesome!"}
    | map_values(ascii_upcase)
    # => {"first": "JANE", "last": "LOPEZ", "status": "AWESOME!"}
    
  • Para iterar sobre um objeto, primeiro precisamos convertê-lo em um array de objetos chave-valor. A função to_entries faz isso.

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

    Nesse ponto, podemos usar funções de iteração de array, como map.

  • A função from_entries é o inverso: converte um array de objetos chave-valor em um objeto.

    [
      {"key":"name", "value":"Jane"},
      {"key":"age", "value":42}
    ] | from_entries                  # => {"name": "Jane", "age": 42}
    
  • Para aplicar um filtro a cada par chave-valor de um objeto, use a função with_entries(filter).

    Por exemplo, dado um objeto que mapeia um nome para uma idade, as chaves e os valores podem ser trocados assim.

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

    produz

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

    with_entries(filter) é o mesmo que

    to_entries | map(filter) | from_entries
    
Editar via GitHub O link abre em uma nova janela ou aba

Aprenda Objetos

A prática está bloqueada

Desbloqueie mais 4 exercícios para praticar Objetos