Como faço para atualizar um único valor em um documento json usando jq?

104

Desculpas se eu esqueci algo muito óbvio; Acabei de encontrar jqe estou tentando usá-lo para atualizar um valor JSON sem afetar os dados circundantes.

Gostaria de canalizar um curlresultado para jq, atualizar um valor e canalizar o JSON atualizado para um curl -X PUT. Algo como

curl http://example.com/shipping.json | jq '.' field: value | curl -X PUT http://example.com/shipping.json

Até agora eu o hackeado usando sed, mas depois de olhar alguns exemplos do |=operador em jqtenho certeza que não preciso deles.

Aqui está um exemplo de JSON - como eu usaria jqpara definir "local": false, preservando o resto do JSON?

{
  "shipping": {
    "local": true,
    "us": true,
    "us_rate": {
      "amount": "0.00",
      "currency": "USD",
      "symbol": "$"
    }
  }
}
STW
fonte

Respostas:

126

Você define os valores de um objeto usando o =operador. |=por outro lado, é usado para atualizar um valor. É uma diferença sutil, mas importante. O contexto dos filtros muda.

Como você está definindo uma propriedade com um valor constante, use o =operador.

.shipping.local = false

Observe que, ao definir um valor para uma propriedade, ela não precisa necessariamente existir. Você pode adicionar novos valores facilmente desta forma.

.shipping.local = false | .shipping.canada = false | .shipping.mexico = true
Jeff Mercado
fonte
10
Esta amostra não é boa para o valor normal. Portanto, se você precisar alterar o valor normal, será necessário adicioná "-lo, como .shipping.local = "new place". Portanto, todo o comando será curl http://example.com/shipping.json | jq '.shipping.local = "new place"'. Caso contrário, você obterá erros estranhos.
BMW
8
@BMW o quê? Está perfeitamente bem aqui. Qualquer valor json válido é válido, isso apenas acontece de ser o literal false. Os valores não precisam ser strings.
Jeff Mercado
@BMW o OP deseja configurá-lo com false. O que há de errado?
SOFe
17

Atualize um valor (define .foo.bar como "novo valor"):

jq '.foo.bar = "new value"' file.json

Atualize um valor usando uma variável (define .foo.bar como "hello"):

variable="hello"; jq --arg variable "$variable" '.foo.bar = $variable' file.json
Paul Chris Jones
fonte
Eu usei isso como um exemplo para renomear um NPM package.json via shell e funcionou 100%, obrigado.
Machado
2
Na verdade, isso não substitui o conteúdo do arquivo. Ele apenas imprime em stdout. Você precisará salvar o stout de volta no arquivo para fazer a alteração persistir. Consulte stackoverflow.com/a/60744617/1626687
spuder
1

uma função semelhante ao operador | = é map. mapa será adequado para evitar a necessidade de um filtro anterior para a matriz ...

imagine que seus dados são uma matriz (muito comum neste exemplo)

[
  {
    "shipping": {
      "local": true,
      "us": true,
      "us_rate": {
        "amount": "1.00",
        "currency": "USD",
        "symbol": "$"
      }
    }
  },
  {
    "shipping": {
      "local": true,
      "us": true,
      "us_rate": {
        "amount": "1.00",
        "currency": "USD",
        "symbol": "$"
      }
    }
  }
]

portanto, é necessário considerar a matriz no código como:

http://example.com/shipping.json | jq '.[] | .shipping.local = "new place"' | curl -X PUT http://example.com/shipping.json

ou usar a função de mapa que é criada para funcionar em cada elemento da matriz como

http://example.com/shipping.json | jq 'map(.shipping.local = "new place")' | curl -X PUT http://example.com/shipping.json

Observação

Para o bem dos que estão aprendendo, você também cometeu alguns erros no uso do jq, apenas considere que ele "lê" o primeiro parâmetro como o programa, portanto, todos os comandos desejados devem ser incluídos na primeira string após chamar o programa.

Thiago Conrado
fonte