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.
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}
Alguns casos frequentes de construção de objetos têm uma sintaxe abreviada.
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"
}
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"}
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
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"
)
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
# }
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
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
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!"]
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