ฉันจะอัปเดตค่าเดียวในเอกสาร json โดยใช้ jq ได้อย่างไร


114

Appologies ถ้าฉันมองข้ามสิ่งที่ชัดเจนมาก ฉันเพิ่งพบjqและกำลังพยายามใช้เพื่ออัปเดตค่า JSON หนึ่งค่าโดยไม่ส่งผลกระทบต่อข้อมูลโดยรอบ

ฉันต้องการไปป์curlผลลัพธ์jqอัปเดตค่าและไพพ์ JSON ที่อัปเดตเป็นไฟล์curl -X PUT. สิ่งที่ต้องการ

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

จนถึงตอนนี้ฉันได้แฮ็กด้วยกันโดยใช้sedแต่หลังจากดูตัวอย่างของตัว|=ดำเนินการในบางส่วนjqแล้วฉันแน่ใจว่าฉันไม่ต้องการสิ่งเหล่านี้

นี่คือตัวอย่าง JSON - ฉันจะใช้jqตั้งค่า"local": falseอย่างไรในขณะที่ยังคงรักษา JSON ที่เหลืออยู่

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

คำตอบ:


137

คุณกำหนดค่าของวัตถุโดยใช้ตัว=ดำเนินการ |=ในทางกลับกันใช้เพื่ออัปเดตค่า มันเป็นความแตกต่างที่ลึกซึ้ง แต่สำคัญ บริบทของตัวกรองเปลี่ยนไป

เนื่องจากคุณกำลังตั้งค่าคุณสมบัติเป็นค่าคงที่ให้ใช้ตัว=ดำเนินการ

.shipping.local = false

โปรดทราบว่าเมื่อตั้งค่าให้กับคุณสมบัติไม่จำเป็นต้องมีอยู่เสมอไป คุณสามารถเพิ่มค่าใหม่ได้อย่างง่ายดายด้วยวิธีนี้

.shipping.local = false | .shipping.canada = false | .shipping.mexico = true

10
ตัวอย่างนี้ไม่ดีสำหรับค่าปกติ ดังนั้นหากคุณต้องการเปลี่ยนค่าปกติคุณต้องเพิ่ม"ด้วยเช่น.shipping.local = "new place". curl http://example.com/shipping.json | jq '.shipping.local = "new place"'ดังนั้นคำสั่งทั้งหมดจะ มิฉะนั้นคุณจะได้รับข้อผิดพลาดแปลก ๆ
BMW

9
@BMW อะไรนะ มันสมบูรณ์ดีที่นี่ ค่า json ที่ถูกต้องนั้นถูกต้องสิ่งนี้จะเป็นค่าลิเทอรัfalseล ค่าไม่จำเป็นต้องเป็นสตริง
Jeff Mercado

@BMW OP falseต้องการที่จะตั้งด้วย มีอะไรผิดปกติ
SOFe

คุณจะตั้งค่า.shipping.<INSERT VAR HERE>ที่กำหนดVAR ใน jq ได้อย่างไร? ตัวอย่างง่ายๆคุณจะแก้ไขอย่างไรjq --arg location local '.shipping.$location = false'เพื่อให้ใช้งานได้
Max Murphy

1
@MaxMurphy:.shipping[$location] = false
Jeff Mercado

22

อัปเดตค่า (set .foo.bar เป็น "new value"):

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

อัปเดตค่าโดยใช้ตัวแปร (ตั้งค่า. foo.bar เป็น "hello"):

variable="hello"; jq --arg variable "$variable" '.foo.bar = $variable' file.json

ฉันใช้สิ่งนี้เป็นตัวอย่างในการเปลี่ยนชื่อแพ็คเกจ NPM.json ผ่านเชลล์และใช้งานได้ 100% ขอบคุณ
Machado

4
สิ่งนี้ไม่ได้แทนที่เนื้อหาของไฟล์ มันพิมพ์ไปยัง stdout เท่านั้น คุณจะต้องบันทึก stout กลับไปที่ไฟล์เพื่อให้การเปลี่ยนแปลงยังคงมีอยู่ ดูstackoverflow.com/a/60744617/1626687
spuder

3

ฟังก์ชันที่คล้ายกับตัวดำเนินการ | = คือแผนที่ แผนที่จะเหมาะสมเพื่อหลีกเลี่ยงความต้องการของตัวกรองก่อนหน้าสำหรับอาร์เรย์ ...

ลองนึกภาพว่าข้อมูลของคุณเป็นอาร์เรย์ (ปกติมากสำหรับตัวอย่างนี้)

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

ดังนั้นจึงจำเป็นต้องพิจารณาอาร์เรย์ในรหัสเป็น:

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

หรือใช้ฟังก์ชั่นแผนที่ที่สร้างขึ้นเพื่อทำงานในทุกองค์ประกอบอาร์เรย์เช่น

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

การสังเกต

เพื่อประโยชน์ของผู้ที่กำลังเรียนรู้คุณได้ทำผิดพลาดบางอย่างในการใช้งาน jq เพียงแค่พิจารณาว่ามัน "อ่าน" พารามิเตอร์ที่ 1 เป็นโปรแกรมดังนั้นคำสั่งที่ต้องการทั้งหมดจะรวมอยู่ในสตริงแรกหลังจากเรียก โปรแกรม.


เหตุใดจึงจำเป็นต้องแตกต่างกับ.[].shipping.local = "new place"?
roaima

1
ความแตกต่างในกรณีนี้คือการตอบสนองโดยใช้ฟังก์ชันแผนที่จะให้อาร์เรย์ของวัตถุในขณะที่ตัวเลือกอื่นคุณจะเรียงลำดับของวัตถุหนึ่งรายการต่อบรรทัด (มีประโยชน์ในการรวมเข้ากับล่ามอื่น ๆ เป็น bash)
Thiago Conrado
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.