Bagaimana cara memperbarui nilai tunggal dalam dokumen json menggunakan jq?

106

Mohon maaf jika saya telah melewatkan sesuatu yang sangat jelas; Saya baru saja menemukan jqdan mencoba menggunakannya untuk memperbarui satu nilai JSON tanpa memengaruhi data di sekitarnya.

Saya ingin menyalurkan curlhasil ke jq, memperbarui nilai, dan menyalurkan JSON yang diperbarui ke curl -X PUT. Sesuatu seperti

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

Sejauh ini saya telah meretasnya bersama-sama menggunakan sed, tetapi setelah melihat beberapa contoh |=operator di jqsaya yakin saya tidak memerlukan ini.

Berikut adalah contoh JSON - bagaimana saya akan menggunakan jquntuk menyetel "local": false, sambil mempertahankan JSON lainnya?

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

Jawaban:

127

Anda menetapkan nilai suatu objek menggunakan =operator. |=di sisi lain digunakan untuk memperbarui nilai. Ini perbedaan yang halus tapi penting. Konteks filter berubah.

Karena Anda menyetel properti ke nilai konstan, gunakan =operator.

.shipping.local = false

Perhatikan bahwa saat menyetel nilai ke properti, itu tidak harus ada. Anda dapat menambahkan nilai baru dengan mudah dengan cara ini.

.shipping.local = false | .shipping.canada = false | .shipping.mexico = true
Jeff Mercado
sumber
10
Sampel ini tidak baik untuk nilai normal. Jadi jika Anda perlu mengubah nilai normal, Anda perlu menambahkannya ", seperti .shipping.local = "new place". Jadi seluruh perintah akan menjadi curl http://example.com/shipping.json | jq '.shipping.local = "new place"'. Jika tidak, Anda akan mendapatkan kesalahan aneh.
BMW
8
@BMW apa? Tidak apa-apa di sini. Nilai json yang valid adalah valid, ini kebetulan adalah literal false. Nilai tidak harus berupa string.
Jeff Mercado
@BMW OP ingin mengaturnya false. Apa yang salah?
SOFe
18

Perbarui nilai (set .foo.bar ke "nilai baru"):

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

Perbarui nilai menggunakan variabel (set .foo.bar menjadi "hello"):

variable="hello"; jq --arg variable "$variable" '.foo.bar = $variable' file.json
Paul Chris Jones
sumber
Saya menggunakan ini sebagai contoh untuk mengganti nama paket NPM.json melalui shell dan berhasil 100%, terima kasih.
Machado
2
Ini sebenarnya tidak menggantikan konten file. Ini hanya mencetak ke stdout. Anda perlu menyimpan bayak kembali ke file untuk membuat perubahan tetap ada. Lihat stackoverflow.com/a/60744617/1626687
spuder
2

fungsi yang mirip dengan operator | = adalah peta. peta akan cocok untuk menghindari persyaratan filter sebelumnya untuk array ...

bayangkan data Anda adalah array (sangat umum untuk contoh ini)

[
  {
    "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": "$"
      }
    }
  }
]

oleh karena itu perlu untuk mempertimbangkan array dalam kode sebagai:

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

atau menggunakan fungsi peta yang dibuat untuk bekerja di setiap elemen array sebagai

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

Pengamatan

Demi mereka yang sedang belajar, Anda juga melakukan beberapa kesalahan dalam penggunaan jq, anggap saja itu "membaca" parameter pertama sebagai program, maka semua perintah yang diinginkan harus dimasukkan dalam string pertama setelah memanggil program.

Thiago Conrado
sumber