JSON Toolkit

JMESPath สำหรับผู้เริ่มต้น: การคิวรีแบบ Projection ที่เหนือกว่า JSONPath

สรุปสำคัญ: JMESPath ปรับรูปชุดออบเจกต์ได้ตรงไปตรงมากว่า JSONPath คู่มือสำหรับผู้เริ่มต้นนี้ครอบคลุมไวยากรณ์, projection, pipe, ฟังก์ชันในตัว และการใช้งานร่วมกับ AWS CLI

ผู้เริ่มต้นอ่านประมาณ 9 นาทีเผยแพร่ 2026-10-31อัปเดต 2026-10-31
ภาพปกสำหรับ JMESPath สำหรับผู้เริ่มต้น

สรุปสั้น: ใช้ JSON Pointer เพื่อระบุตำแหน่งตามตำแหน่ง ใช้ JSONPath เพื่อกรองหรือเรียกซ้ำ และใช้ JMESPath เมื่อต้องปรับรูปผลลัพธ์หรือ project บน command line; ฟิลด์เดียวที่รู้อยู่แล้วไม่ต้องใช้ทั้งสองแบบ

ถ้าเป้าหมายของคุณคือการปรับรูปชุดออบเจกต์ให้เป็นรูปแบบอื่น JMESPath มักตรงไปตรงมากว่า JSONPath มันไม่ได้ค้นหาโหนด แต่สร้างผลลัพธ์ขึ้นมา

1. JMESPath คืออะไร

JMESPath คือภาษาคิวรีที่ออกแบบมาเพื่อ JSON โดยเฉพาะ เดิมถูกสร้างขึ้นเพื่อกรองผลลัพธ์ของ AWS CLI และต่อมาได้แพร่กระจายไปยังหลายภาษาผ่าน implementation อย่าง jmespath.js, jmespath.py และ go-jmespath เป้าหมายของมันต่างจาก JSONPath:

  • JSONPath เน้นการเลือกชุดโหนดตามพาธและเงื่อนไข แล้วคืนค่ากลับเป็นชุดโหนด;
  • JMESPath เน้นการแปลง JSON ขาเข้า แล้วคืนค่าในรูปร่างใดก็ได้

ความต่างนี้ทำให้ JMESPath โดดเด่นเป็นพิเศษในเรื่อง list projection, การเปลี่ยนชื่อฟิลด์ และการตัดทอนผลลัพธ์ เช่น ลดฟิลด์ยี่สิบฟิลด์จากการตอบกลับของ API ให้เหลือสามฟิลด์ที่ frontend ต้องการจริง ๆ ถ้าคุณยังไม่ได้อ่านพื้นฐานของ JSONPath เริ่มจาก ภาษา JSONPath ในทางปฏิบัติ

2. ไวยากรณ์พื้นฐาน: จาก Identifier ถึง Index

JMESPath ใช้สัญลักษณ์น้อยกว่า JSONPath และอ่านแล้วเหมือนนิพจน์การดึงข้อมูลมากกว่า:

ไวยากรณ์ ความหมาย ตัวอย่าง
name เข้าถึงสมาชิกของออบเจกต์ people
a.b เข้าถึงสมาชิกที่ซ้อนกัน store.bicycle.color
[0] เข้าถึงดัชนีของ array people[0]
[-1] เข้าถึงสมาชิกตัวสุดท้าย people[-1]
[0:2] Slice โดยนับจุดเริ่มและไม่นับจุดสิ้นสุด people[0:2]
[*] List projection people[*].name
[] Flatten projection people[].tags[]
[?condition] Filter projection people[?age > 18]
{key: expr} Multi-select hash {name: name, age: age}
[expr, expr] Multi-select list [name, age]
| ส่งผลลัพธ์ฝั่งซ้ายเข้าไปฝั่งขวา people[*].age | [0]

ตัวอย่างเล็ก ๆ:

{
  "people": [
    { "name": "Alice", "age": 31, "city": "Shanghai" },
    { "name": "Bob", "age": 17, "city": "Beijing" }
  ]
}
people[0].name      → "Alice"
people[-1].city     → "Beijing"
people[0:2].name    → ["Alice", "Bob"]

สังเกตว่าทำไม people[0:2].name คืนค่าเป็น array: slice ให้ผลเป็นลิสต์ และ .name ที่ตามมาจะถูก project โดยอัตโนมัติลงบนทุกสมาชิกของลิสต์นั้น นี่คือความต่างที่ใหญ่ที่สุดระหว่าง JMESPath กับการเข้าถึงออบเจกต์แบบปกติ

3. Projection: เปลี่ยนลิสต์หนึ่งให้เป็นอีกลิสต์หนึ่ง

Projection คือแนวคิดหลักของ JMESPath มันทำงานสองขั้น: ประเมินสมาชิกทุกตัวของลิสต์ แล้วรวบรวมผลลัพธ์เป็นลิสต์ใหม่ สมาชิกที่ประเมินแล้วได้ null จะถูกตัดทิ้งอัตโนมัติ

people[*].name                   // ["Alice", "Bob"]
people[*].{name: name, age: age} // a list of objects
people[?age > 18].name           // ["Alice"]

บรรทัดที่สองคือนิพจน์ projection แบบฉบับ: people[*].{name: name, age: age} มันสร้างสมาชิกทุกตัวขึ้นใหม่เป็น { "name": ..., "age": ... } และทิ้งฟิลด์ city ที่เกินมา เมื่อเทียบกับ JSONPath ที่ให้โหนดแล้วคุณต้อง map ในโค้ดต่อ แบบนี้ประหยัดลูปไปหนึ่งรอบ

Projection สองแบบที่ควรแยกให้ออก:

  • [*] รักษาโครงสร้างลิสต์เดิมไว้และข้ามค่า null;
  • [] เป็น flatten projection ที่ยุบลิสต์ซ้อนหนึ่งชั้นก่อน ซึ่งเหมาะกับนิพจน์อย่าง people[].tags[] ที่ต้องการ "แท็กทั้งหมดของทุกคน"

4. Pipe และ Multi-Select

Pipe | หมายถึง "หยุด projection ปัจจุบันแล้วถือผลลัพธ์เป็นอินพุตใหม่" การใช้ที่พบบ่อยที่สุดคือการเอาดัชนีหลัง projection:

people[*].name | [0]           → "Alice"
people[*].age | sort(@) | [-1] → the maximum age

ถ้าไม่มี pipe, people[*].name[0] จะถูกตีความเป็น "เอาตัวอักษรตัวแรกของทุกชื่อ" ซึ่งไม่ใช่สิ่งที่คุณต้องการ Pipe เป็นสัญลักษณ์ที่ถูกละเลยง่ายที่สุดและมีประโยชน์ที่สุดใน JMESPath

Multi-select มีสองรูปแบบ:

// Multi-select hash: the result is an object
people[0].{name: name, age: age}

// Multi-select list: the result is an array
people[0].[name, age]

Multi-select hash เหมาะกับการสร้างผลลัพธ์ที่มีชื่อฟิลด์ ส่วน multi-select list เหมาะกับการใช้ตามตำแหน่ง ทั้งสองแบบซ้อนใน projection ได้ แต่ต้องระวัง: ใน multi-select hash คีย์ที่ค่าของมันเป็น null จะยังคงอยู่ ขณะที่ projection จะทิ้งสมาชิก null ทั้งตัว

5. ฟังก์ชันในตัว

มาตรฐาน JMESPath กำหนดชุดฟังก์ชันไว้ ฟังก์ชันที่พบบ่อยได้แก่:

ฟังก์ชัน จุดประสงค์ ตัวอย่าง
length() หาความยาว length(people)
sort() เรียงค่า sort(people[*].age)
sort_by() เรียงตามฟิลด์ sort_by(people, &age)
max() / min() ค่าสูงสุด / ต่ำสุด max(people[*].age)
sum() รวมค่า sum(people[*].age)
keys() ดึงคีย์ของออบเจกต์ keys(people[0])
contains() ตรวจว่ามีค่าอยู่หรือไม่ contains(name, "Ali")
to_string() แปลงเป็นสตริง to_string(age)

อาร์กิวเมนต์ตัวที่สองของ sort_by คือนิพจน์ & ซึ่งหมายถึง "ดึงฟิลด์นี้จากสมาชิกแต่ละตัว":

sort_by(people, &age)[*].name

ฟังก์ชันเหล่านี้ทำให้ JMESPath ทำการ aggregate อย่างง่ายได้ ขณะที่ JSONPath ถูกออกแบบมาเพื่อการเลือกเท่านั้น การรวมผลและการจัดกลุ่มมักต้องใช้ jq หรือเขียนโค้ดเอง

6. เปรียบเทียบกับ JSONPath แบบเคียงข้าง

มิติ JSONPath JMESPath
เป้าหมายหลัก เลือกโหนด แปลงข้อมูล
สัญลักษณ์ราก $ ไม่มี; เขียนชื่อฟิลด์โดยตรง
โหนดปัจจุบัน @ @ (เฉพาะในอาร์กิวเมนต์ของฟังก์ชัน)
ตัวกรอง [?(@.age > 18)] [?age > 18]
Wildcard [*] [*] หรือ []
สร้างออบเจกต์ใหม่ ไม่รองรับ {name: name}
Pipe ไม่รองรับ |
มาตรฐาน RFC 9535 ข้อกำหนด JMESPath

แนวทางตัดสินใจหนึ่งประโยค:

  • ใช้ JSONPath เมื่อต้องการเพียงค้นหาโหนดที่ตรงเงื่อนไข;
  • ใช้ JMESPath เมื่อต้องปรับรูปผลลัพธ์ให้เป็นอย่างที่ frontend คาดหวัง;
  • ไม่ต้องใช้ทั้งสองแบบเมื่ออ่านฟิลด์เดียวที่รู้อยู่แล้ว; เข้าถึงพร็อพเพอร์ตี้โดยตรงก็พอ

ถ้าผลลัพธ์การคิวรีต้องถูกเขียนกลับลงเอกสาร ทั้งสองภาษาไม่เหมาะ ให้ใช้ JSON Pointer และแพตช์แทน ดู JSON Pointer, Patch และ Merge Patch

7. JMESPath ใน AWS CLI

พารามิเตอร์ --query ของ AWS CLI คือ JMESPath ซึ่งเป็นการใช้งานที่แพร่หลายที่สุด:

aws ec2 describe-instances \
  --query 'Reservations[].Instances[].{Id: InstanceId, State: State.Name, Type: InstanceType}' \
  --output table

คำสั่งนี้ทำสามสิ่ง: ยุบลิสต์ซ้อนสองชั้นด้วย [], เก็บไว้เพียงสามฟิลด์ด้วย multi-select hash และแสดงผลเป็นตารางด้วย --output table ถ้าใช้ JSONPath คุณจะต้องเพิ่มระดับอีกและยังไม่ได้ผลลัพธ์แบบ "เปลี่ยนชื่อพร้อมตัดทอน"

รูปแบบอื่นที่พบบ่อย:

# เฉพาะ instance ที่กำลังทำงาน
aws ec2 describe-instances --query 'Reservations[].Instances[?State.Name==`running`].[InstanceId,PublicIpAddress]'

# ค่าของแท็ก Name
aws ec2 describe-instances --query 'Reservations[].Instances[].Tags[?Key==`Name`].Value[]'

โปรดสังเกตว่า backtick ใช้ล้อม literal ไม่ใช่สตริง ใน AWS CLI สตริงใช้ single quote และ JSON literal ใช้ backtick ความต่างนี้เป็นหนึ่งในข้อผิดพลาดที่ผู้เริ่มต้นพบมากที่สุด

8. ข้อผิดพลาดที่พบบ่อย

  • สับสนระหว่าง [*] กับ []: แบบแรกคงการซ้อนไว้ แบบหลังยุบหนึ่งชั้น และโครงสร้างผลลัพธ์ที่ได้ต่างกันโดยสิ้นเชิง;
  • ลืม pipe: people[*].name[0] เอาตัวอักษรตัวแรกของทุกชื่อ ไม่ใช่ชื่อตัวแรก;
  • เขียน @ ในตัวกรอง: ตัวกรองของ JMESPath ใช้ชื่อฟิลด์โดยตรง ดังนั้น [?@.age > 18] จึงผิด;
  • ถือว่า null เป็นสตริงว่าง: projection ทิ้ง null แต่ multi-select hash เก็บคีย์ไว้;
  • ใส่ double quote รอบ literal ใน AWS CLI: shell จะขยายมันก่อนและเขียนนิพจน์ใหม่

คำแนะนำในการดีบัก: ตรวจสอบนิพจน์กับอินพุตที่เล็กที่สุดก่อนนำไปใช้กับข้อมูลจริง และเพิ่ม --output json ใน AWS CLI เพื่อดูผลลัพธ์ดิบ สำหรับการแก้ไขและจัดรูปแบบ JSON ในชีวิตประจำวัน การใช้ร่วมกับ ตัวแก้ไข JSON และเครื่องมือบรรทัดคำสั่ง จะทำให้การหาพาธฟิลด์เร็วขึ้นมาก

คำถามที่พบบ่อย

ใช้ JMESPath และ JSONPath ร่วมกันได้ไหม

ได้ แต่โดยปกติไม่จำเป็น แนวทางที่พบบ่อยคือตัดทอนออบเจกต์เล็ก ๆ ด้วย JMESPath แล้วเข้าถึงพร็อพเพอร์ตี้แบบปกติในโค้ด ถ้าต้องระบุตำแหน่งตามพาธแล้วแก้ไขจริง ๆ ให้ JSONPath อ่านและ JSON Pointer เขียน ซึ่งเป็นการแบ่งงานที่ชัดเจนกว่า

ทำไม people[*].name ไม่ได้คืนค่าเป็นสตริงเดียว

เพราะ [*] เป็น projection และผลลัพธ์เป็นลิสต์เสมอ แม้จะมีคนเพียงคนเดียว ถ้าต้องการค่าเดียว ให้เพิ่ม pipe และดัชนี: people[*].name | [0]

ค่า null ใน projection เกิดอะไรขึ้น

List projection จะข้ามสมาชิกที่ประเมินแล้วได้ null โดยอัตโนมัติ ผลลัพธ์จึงอาจสั้นกว่าลิสต์เดิม ส่วน multi-select hash จะเก็บคีย์ไว้และรักษาค่า null ไว้ ซึ่งสำคัญเมื่อสร้างการตอบกลับของ API

JMESPath ทำ aggregation และการจัดกลุ่มได้ไหม

ทำ aggregation พื้นฐานได้ด้วย sum(), max() และ sort_by() การจัดกลุ่ม, join และ window function อยู่นอกมาตรฐาน ปล่อยการวิเคราะห์ซับซ้อนให้ jq, SQL หรือโค้ด

จะตัดสินใจระหว่าง JMESPath กับ JSONPath อย่างไร

ใช้ JSONPath เมื่อต้องเลือกโหนดตามพาธและเงื่อนไขแล้วได้ชุดโหนด; ใช้ JMESPath เมื่อต้องปรับรูปผลลัพธ์ให้เป็นอย่างที่ frontend คาดหวัง พร้อมเปลี่ยนชื่อและตัดทอนฟิลด์ เมื่ออ่านฟิลด์เดียวที่รู้อยู่แล้ว ไม่ต้องใช้ทั้งสองแบบ; เข้าถึงพร็อพเพอร์ตี้โดยตรงก็พอ

ควรใช้ pipe เพื่อเอาค่าแรกของ projection ไหม

ควร people[*].name เป็น projection ผลลัพธ์จึงเป็นลิสต์เสมอ; ถ้าไม่มี pipe, people[*].name[0] จะเอาตัวอักษรตัวแรกของทุกชื่อ เขียน people[*].name | [0] เพื่อให้ได้ค่าแรก

แหล่งอ้างอิง

เครื่องมือที่เกี่ยวข้อง

บทความที่เกี่ยวข้อง

ภาษา JSONPath ในทางปฏิบัติ

ในปี 2024 JSONPath มีมาตรฐานอย่างเป็นทางการในที่สุด นั่นคือ RFC 9535 บทความนี้อธิบายไวยากรณ์ ความหมายของตัวกรอง ฟังก์ชัน และความแตกต่างเชิงประวัติศาสตร์ระหว่าง implementation

ระดับกลางอ่านประมาณ 12 นาทีอัปเดต 2026-10-30

Editor, Command Line และ Toolchain สำหรับ Automation

Editor แก้ปัญหา "เห็นชัด แก้ไขถูก" ขณะที่ command line แก้ปัญหา "ทำทีละมาก ๆ และทำซ้ำได้" แต่ละฝ่ายมีเครื่องมือไม่กี่ตัวที่ยังใช้ได้ดีไปอีกทศวรรษ

ผู้เริ่มต้นอ่านประมาณ 10 นาทีอัปเดต 2026-10-30

JSON Pointer, Patch และ Merge Patch

ข้อกำหนดสั้นสามฉบับประกอบกันเป็นโปรโตคอลการเปลี่ยนแปลง: Pointer ระบุตำแหน่ง, Patch แก้ไขอย่างแม่นยำ, Merge Patch รวมบางส่วน การเลือกผิดจะสร้างปัญหาให้ array และ concurrency

ระดับกลางอ่านประมาณ 12 นาทีอัปเดต 2026-10-30