การแปลงและสร้างออบเจกต์ JSON ด้วย jq
ปรับรูปแบบข้อมูลด้วย map, to_entries และการสร้างออบเจกต์ เพื่อสร้างข้อมูล JSON ชุดใหม่
การแปลงและสร้างออบเจกต์ JSON ด้วย jq เป็นบทเรียน Linux Command Line & Bash Scripting Mastery ฟรีบน CoddyKit นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Linux Command Line & Bash Scripting Mastery และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Linux Command Line & Bash Scripting Mastery มีบทเรียนทั้งหมด 4 บทเรียน
เหตุใดจึงต้องแปลง JSON
JSON ดิบจาก API หรือไฟล์บันทึกมักไม่ได้มีรูปแบบตรงตามที่คุณต้องการ คุณอาจได้รับออบเจ็กต์ขนาดใหญ่แต่ต้องการเพียงบางฟิลด์ หรือต้องการเปลี่ยนชื่อคีย์ ทำโครงสร้างที่ซ้อนกันให้แบนราบ หรือสร้างข้อมูลใหม่ทั้งหมดเพื่อส่งไปยังบริการอื่น
jq เป็นตัวประมวลผล JSON บรรทัดคำสั่งที่มีขนาดเล็กแต่ทรงพลัง ทำให้การแปลงเหล่านี้ทำได้ในกระบวนการต่อเนื่องเดียว ในบทเรียนนี้คุณจะได้เรียนรู้เทคนิคหลักสามอย่างสำหรับปรับรูปข้อมูล:
- การสร้างออบเจ็กต์ — สร้างออบเจ็กต์ JSON ใหม่ตั้งแต่ต้น
- map — ใช้การแปลงกับทุกองค์ประกอบของอาร์เรย์
- to_entries / from_entries — มองคู่คีย์-ค่าในออบเจ็กต์เป็นอาร์เรย์ เพื่อให้กรองและสร้างกลับขึ้นมาใหม่ได้
ตัวอย่างทั้งหมดสมมติว่าติดตั้ง jq แล้ว (apt install jq / brew install jq)
พื้นฐานการสร้างออบเจ็กต์
ความสามารถพื้นฐานที่สุดของ jq คือ การสร้างออบเจ็กต์: ครอบนิพจน์ด้วย {} เพื่อสร้างออบเจ็กต์ JSON ใหม่ คุณเลือกได้ว่าจะใส่ฟิลด์ใดบ้างและจะตั้งชื่อว่าอะไร
ไวยากรณ์:
{ newKey: .existingField }— เปลี่ยนชื่อฟิลด์{ name, age }— รูปแบบย่อเมื่อคีย์ใหม่ตรงกับชื่อฟิลด์{ total: (.price * .qty) }— คำนวณค่าในบรรทัดเดียว
ส่วนย่อยของคำสั่งด้านล่างอ่าน JSON ของสินค้าและสร้างรูปแบบที่กระชับขึ้น โดยมีฟิลด์ subtotal ที่คำนวณแล้ว
#!/usr/bin/env bash
# Object construction: pick and rename fields
product='{
"id": 42,
"name": "Widget Pro",
"price": 9.99,
"qty": 3,
"warehouse": "EU-West"
}'
echo "$product" | jq '{
productId: .id,
name,
subtotal: (.price * .qty)
}'การสร้างออบเจ็กต์จากข้อมูลที่ซ้อนกัน
JSON ในการใช้งานจริงมักมีโครงสร้างซ้อนกัน jq ช่วยให้คุณเข้าถึงเส้นทางที่ซ้อนกันภายในตัวสร้างออบเจ็กต์ และทำให้โครงสร้างแบนราบได้ในเวลาเดียวกัน
ใช้สัญกรณ์เส้นทางแบบจุดภายในนิพจน์ค่าของตัวสร้าง:
{ city: .address.city }{ lat: .location.coords.lat }
ตัวอย่างด้านล่างนำระเบียนผู้ใช้ที่ซ้อนกันลึกมาสร้างเป็นสรุปแบบแบนราบ ซึ่งเหมาะสำหรับแถวส่วนหัวของ CSV หรือเนื้อหาคำขอ API
#!/usr/bin/env bash
user='{
"id": "u-001",
"profile": {
"displayName": "Ada Lovelace",
"contact": { "email": "ada@example.com", "phone": "+44-700" }
},
"plan": "pro"
}'
echo "$user" | jq '{
id,
name: .profile.displayName,
email: .profile.contact.email,
plan
}'การแปลงอาร์เรย์ด้วย map
map(expr) เทียบเท่ากับการวนทำกับทุกองค์ประกอบใน jq: ใช้ expr กับทุกองค์ประกอบของอาร์เรย์อินพุต และส่งคืนอาร์เรย์ใหม่ที่มีความยาวเท่าเดิม
ประเด็นสำคัญ:
map(expr)เป็นรูปแบบย่อของ[.[] | expr]- นิพจน์ภายในอาจเป็นตัวกรอง jq ใด ๆ ก็ได้ รวมถึงการสร้างออบเจ็กต์
- เชื่อมกับ
select()เพื่อกรองก่อนแปลงข้อมูล
ส่วนย่อยของคำสั่งนี้ประมวลผลรายการคำสั่งซื้อ โดยเก็บไว้เฉพาะฟิลด์ที่จำเป็นสำหรับรายการจัดส่ง
#!/usr/bin/env bash
orders='[
{"orderId": 1, "customer": "Alice", "total": 42.50, "status": "shipped"},
{"orderId": 2, "customer": "Bob", "total": 18.00, "status": "pending"},
{"orderId": 3, "customer": "Carol", "total": 99.99, "status": "shipped"}
]'
# Produce a shipping manifest: only shipped orders, slim fields
echo "$orders" | jq '[
.[] | select(.status == "shipped") | {
id: .orderId,
recipient: .customer,
amount: .total
}
]'map กับฟิลด์ที่คำนวณแล้ว
ภายใน map คุณสามารถคำนวณค่าใหม่ แปลงชนิดข้อมูล และรวมฟิลด์ต่าง ๆ ได้ ไม่ใช่เพียงคัดลอกข้อมูล รูปแบบที่ใช้บ่อย ได้แก่:
- การแทรกข้อความ:
"\(.first) \(.last)" - เลขคณิต:
(.price * 1.2 | round)สำหรับการบวกราคาเพิ่ม 20% - เงื่อนไข:
if .score >= 90 then "A" else "B" end
ตัวอย่างด้านล่างเพิ่มข้อมูลให้รายการพนักงาน โดยเพิ่ม fullName ที่คำนวณแล้วและป้ายกำกับ seniority ตามจำนวนปีของประสบการณ์
#!/usr/bin/env bash
staff='[
{"first": "Grace", "last": "Hopper", "years": 15},
{"first": "Alan", "last": "Turing", "years": 4},
{"first": "Linus", "last": "Torvalds","years": 9}
]'
echo "$staff" | jq 'map({
fullName: "\(.first) \(.last)",
years,
seniority: (if .years >= 10 then "senior" elif .years >= 5 then "mid" else "junior" end)
})'ทำความเข้าใจ to_entries
to_entries แปลงออบเจ็กต์ JSON เป็นอาร์เรย์ของคู่ {key, value} ทำให้ใช้การดำเนินการกับอาร์เรย์ เช่น map, select และ sort กับฟิลด์ของออบเจ็กต์ได้ ซึ่งไม่สามารถทำกับออบเจ็กต์โดยตรง
ตัวอย่างการแปลง:
- อินพุต:
{"a": 1, "b": 2} - เอาต์พุต:
[{"key": "a", "value": 1}, {"key": "b", "value": 2}]
การดำเนินการย้อนกลับคือ from_entries ซึ่งแปลงอาร์เรย์นั้นกลับเป็นออบเจ็กต์ ทั้งสองอย่างรวมกันเป็นรูปแบบ to_entries | map(...) | from_entries สำหรับแปลงข้อมูลระดับออบเจ็กต์
#!/usr/bin/env bash
# Demonstrate to_entries and from_entries
config='{"host": "db.local", "port": 5432, "ssl": true}'
echo "--- to_entries output ---"
echo "$config" | jq 'to_entries'
echo "--- round-trip back to object ---"
echo "$config" | jq 'to_entries | from_entries'การกรองคีย์ด้วย to_entries
การใช้งาน to_entries ที่เป็นประโยชน์อย่างยิ่งคือ การกรองแบบไดนามิกว่าควรเก็บหรือลบคีย์ใด โดยพิจารณาจากชื่อคีย์เอง ซึ่งการสร้างออบเจ็กต์ทำไม่ได้เมื่อไม่ทราบชื่อคีย์ล่วงหน้า
รูปแบบ:
to_entries | map(select(.key | test("regex"))) | from_entriesto_entries | map(select(.key != "secret")) | from_entries
ส่วนย่อยของคำสั่งด้านล่างลบคีย์ทั้งหมดที่ขึ้นต้นด้วยขีดล่าง ซึ่งเป็นฟิลด์ภายในหรือฟิลด์ส่วนตัว ก่อนส่งต่อออบเจ็กต์การกำหนดค่าไปยังบริการภายนอก
#!/usr/bin/env bash
raw_config='{
"endpoint": "https://api.example.com",
"timeout": 30,
"_internalToken": "s3cr3t",
"_debugMode": true,
"retries": 3
}'
# Remove any key starting with underscore
echo "$raw_config" | jq '
to_entries
| map(select(.key | startswith("_") | not))
| from_entries
'การเปลี่ยนชื่อคีย์แบบไดนามิกด้วย to_entries
การสร้างออบเจ็กต์ใช้เปลี่ยนชื่อคีย์เมื่อคุณทราบชื่อขณะเขียน แต่ to_entries ช่วยให้คุณเปลี่ยนชื่อคีย์ โดยใช้โปรแกรม ได้ เช่น แปลง camelCase เป็น snake_case หรือเพิ่มคำนำหน้า
ภายใน map คุณจะอัปเดตฟิลด์ .key ของแต่ละรายการ แล้วส่งต่อไปยัง from_entries:
map(.key |= gsub("(?<=[a-z])(?=[A-Z])"; "_") | .key |= ascii_downcase)— แปลง camelCase เป็น snake_casemap(.key |= "app_" + .)— เพิ่มคำนำหน้าให้ทุกคีย์
ตัวอย่างนี้เพิ่มคำนำหน้า APP_ ให้ชื่อตัวแปรสภาพแวดล้อมทั้งหมด เพื่อจัดกลุ่มชื่อก่อนแทรกเข้าไปในคอนเทนเนอร์
#!/usr/bin/env bash
env_vars='{"host": "localhost", "port": "8080", "debug": "false"}'
# Add APP_ prefix and uppercase all keys
echo "$env_vars" | jq '
to_entries
| map({ key: ("APP_" + (.key | ascii_upcase)), value })
| from_entries
'with_entries: รูปแบบย่อที่สะดวก
รูปแบบ to_entries | map(...) | from_entries ถูกใช้บ่อยมาก จน jq มีรูปแบบย่อให้ใช้ นั่นคือ with_entries(expr)
ให้ผลเทียบเท่ากันทุกประการ แต่กระชับกว่า:
with_entries(.value |= . * 2)— คูณค่าตัวเลขทุกค่าด้วยสองwith_entries(select(.value != null))— ลบคีย์ที่มีค่าเป็นค่าว่างwith_entries(.key |= ascii_upcase)— เปลี่ยนคีย์ทั้งหมดเป็นตัวพิมพ์ใหญ่
ส่วนย่อยของคำสั่งนี้ลบคีย์ทั้งหมดที่มีค่าเป็น null หรือสตริงว่าง ซึ่งเป็นขั้นตอนทำความสะอาดที่ใช้บ่อยก่อนส่งคำขอ PATCH ไปยัง REST API
#!/usr/bin/env bash
patch_body='{
"name": "Mehmet",
"email": "",
"phone": null,
"city": "Istanbul"
}'
# Drop empty/null fields before PATCH
cleaned=$(echo "$patch_body" | jq '
with_entries(select(.value != null and .value != ""))
')
echo "Cleaned payload:"
echo "$cleaned"
# In practice you would pipe to curl:
# curl -s -X PATCH https://api.example.com/users/1 \
# -H "Content-Type: application/json" \
# -d "$cleaned"การรวม map และการสร้างออบเจ็กต์ในกระบวนการต่อเนื่อง
การแปลงข้อมูลจริงมักเชื่อมการดำเนินการ jq หลายอย่างเข้าด้วยกัน กระบวนการต่อเนื่องทั่วไปสำหรับเตรียมข้อมูลส่งไปยัง API อาจทำดังนี้:
- กรองอาร์เรย์อินพุตด้วย
map(select(...)) - ปรับรูปแต่ละองค์ประกอบด้วยการสร้างออบเจ็กต์
- เพิ่มฟิลด์ที่คำนวณแล้ว
- เรียงลำดับผลลัพธ์
ตัวอย่างด้านล่างอ่านรายการตัวชี้วัดของเซิร์ฟเวอร์ เก็บเฉพาะเซิร์ฟเวอร์ที่มีการใช้งาน CPU สูง และสร้างข้อมูลแจ้งเตือนแบบกระชับพร้อมส่งด้วย POST ไปยังเว็บฮุก
#!/usr/bin/env bash
metrics='[
{"host": "web-01", "cpu": 23, "mem": 60, "region": "eu"},
{"host": "web-02", "cpu": 91, "mem": 88, "region": "eu"},
{"host": "db-01", "cpu": 78, "mem": 95, "region": "us"},
{"host": "db-02", "cpu": 12, "mem": 40, "region": "us"}
]'
alerts=$(echo "$metrics" | jq '[
.[] | select(.cpu > 75 or .mem > 85) | {
server: .host,
region,
severity: (if .cpu > 90 or .mem > 90 then "critical" else "warning" end),
metrics: { cpu: .cpu, mem: .mem }
}
] | sort_by(.severity)')
echo "$alerts"การสร้างออบเจ็กต์ JSON ใหม่จากหลายแหล่ง
jq สามารถผสานอินพุตและสร้างออบเจ็กต์ที่ดึงข้อมูลจาก JSON หลายแหล่งได้ โดยใช้ ตัวดำเนินการบวก + และ การผูกตัวแปร ด้วย as $var
รูปแบบที่มีประโยชน์:
obj1 + obj2— ผสานออบเจ็กต์สองตัว โดยค่าด้านขวาจะชนะเมื่อคีย์ขัดแย้งกัน--argjson— ส่งเอกสาร JSON ตัวที่สองเป็นตัวแปร$ENV— อ่านตัวแปรสภาพแวดล้อมโดยตรงภายใน jq
ส่วนย่อยของคำสั่งนี้ผสานการกำหนดค่าพื้นฐานกับการเขียนทับเฉพาะสภาพแวดล้อม ซึ่งเป็นรูปแบบที่ใช้บ่อยสำหรับจัดการการกำหนดค่าแอปพลิเคชันแบบ 12-factor ในสคริปต์เชลล์
#!/usr/bin/env bash
base_config='{
"logLevel": "info",
"timeout": 30,
"retries": 3,
"database": "postgres://db.local/app"
}'
env_overrides='{
"logLevel": "debug",
"database": "postgres://db.staging/app_staging"
}'
# Merge: overrides win on conflicts
merged=$(echo "$base_config" | jq --argjson overrides "$env_overrides" '. + $overrides')
echo "Merged config:"
echo "$merged"ตรวจสอบความเข้าใจ: to_entries กับ map
คุณมีออบเจ็กต์ JSON ต่อไปนี้ และต้องการลบคีย์ทั้งหมดที่มี ค่าน้อยกว่า 0 เพื่อสร้างออบเจ็กต์ใหม่ที่มีเฉพาะค่าที่ไม่ติดลบ นิพจน์ jq ใดทำงานนี้ได้ถูกต้อง
อินพุต: {"a": 10, "b": -3, "c": 0, "d": 5}
สรุปบทเรียน: การแปลง JSON ด้วย jq
คุณได้เรียนรู้เทคนิคสำคัญสำหรับปรับรูป JSON ด้วย jq แล้ว:
- การสร้างออบเจ็กต์
{}— สร้างออบเจ็กต์ใหม่โดยเลือก เปลี่ยนชื่อ และคำนวณฟิลด์จากอินพุต map(expr)— ใช้การแปลงใด ๆ กับทุกองค์ประกอบของอาร์เรย์ รวมถึงการสร้างออบเจ็กต์ที่ซ้อนกันและการใช้select()เพื่อกรองto_entries/from_entries— แปลงออบเจ็กต์เป็นอาร์เรย์ของคู่{key, value}เพื่อให้ดำเนินการกับคีย์และค่าแบบอาร์เรย์ได้ แล้วแปลงกลับwith_entries(expr)— รูปแบบย่อของกระบวนการต่อเนื่อง to_entries → map → from_entries ทั้งชุด- การผสานออบเจ็กต์ ด้วย
+และ--argjsonสำหรับข้อมูลจากหลายแหล่ง
องค์ประกอบเหล่านี้นำมาประกอบกันได้: กรองด้วย select ปรับรูปด้วยการสร้างออบเจ็กต์ เพิ่มข้อมูลด้วยฟิลด์ที่คำนวณแล้ว และเชื่อมทั้งหมดเข้าด้วยกันในนิพจน์ jq เดียวที่อ่านง่าย เมื่อเชี่ยวชาญรูปแบบเหล่านี้แล้ว คุณจะจัดการข้อมูล JSON แทบทุกชนิดได้โดยตรงในเชลล์ โดยไม่ต้องเขียนสคริปต์เฉพาะด้วย Python หรือ Node
คำถามที่พบบ่อย
บทเรียน “การแปลงและสร้างออบเจกต์ JSON ด้วย jq” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “การแปลงและสร้างออบเจกต์ JSON ด้วย jq” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Linux Command Line & Bash Scripting Mastery ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Linux Command Line & Bash Scripting Mastery มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “การแปลงและสร้างออบเจกต์ JSON ด้วย jq”
ปรับรูปแบบข้อมูลด้วย map, to_entries และการสร้างออบเจกต์ เพื่อสร้างข้อมูล JSON ชุดใหม่ คุณปฏิบัติ Linux Command Line & Bash Scripting Mastery ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Linux Command Line & Bash Scripting Mastery หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Linux Command Line & Bash Scripting Mastery บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 2 จากทั้งหมด 4 บทเรียน
บทเรียน “การแปลงและสร้างออบเจกต์ JSON ด้วย jq” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Linux Command Line & Bash Scripting Mastery นี้ได้ไหม
ได้ บทเรียน Linux Command Line & Bash Scripting Mastery ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การกรองและเลือก JSON ด้วยไปป์ไลน์ jq
- การแปลงและสร้างออบเจกต์ JSON ด้วย jq
- การใช้ REST API ด้วย curl และ jq ร่วมกัน
- การแก้ไขไฟล์การกำหนดค่า YAML ด้วย yq