JSON Toolkit

JMESPath למתחילים: שאילתות הטלה שמנצחות את JSONPath

שורה תחתונה: JMESPath מעצב קבוצות של אובייקטים בצורה ישירה יותר מ-JSONPath. המדריך למתחילים הזה מכסה תחביר, הטלות, צינורות, פונקציות מובנות ושימוש ב-AWS CLI.

מתחילכ-9 דקות קריאהפורסם 2026-10-31עודכן 2026-10-31
עטיפה עבור JMESPath למתחילים

שורה תחתונה: השתמשו ב-JSON Pointer כדי לאתר לפי מיקום, ב-JSONPath כדי לסנן או לחזור רקורסיבית, וב-JMESPath כשצריך לעצב מחדש את התוצאה או להטיל אותה בשורת הפקודה; שדה יחיד מוכר לא צריך אף אחד מהם.

אם המטרה שלכם היא לעצב מחדש קבוצת אובייקטים לצורה אחרת, JMESPath לרוב ישיר יותר מ-JSONPath. הוא לא מחפש צמתים; הוא בונה תוצאה.

1. מהו JMESPath

JMESPath היא שפת שאילתות שנבנתה במיוחד עבור JSON. היא נוצרה במקור לסינון פלט של AWS CLI ואחר כך התפשטה לשפות רבות דרך מימושים כמו jmespath.js, jmespath.py ו-go-jmespath. המטרה שלה שונה מ-JSONPath:

  • JSONPath מתמקד בבחירת קבוצת צמתים לפי נתיב ותנאי, ומחזיר קבוצת צמתים;
  • JMESPath מתמקד בהמרת ה-JSON שנכנס ומחזיר ערך בכל צורה.

ההבדל הזה הופך את JMESPath למיוחדת בטוב שלה בהטלות רשימות, שינוי שמות שדות וצמצום תוצאות, למשל צמצום עשרים שדות מתגובת API לשלושת השדות שהפרונט באמת צריך. אם עוד לא קראתם את היסודות של JSONPath, התחילו עם שפת השאילתות JSONPath בפועל.

2. תחביר בסיסי: ממזהים ועד לאינדקסים

JMESPath משתמש בפחות סימנים מ-JSONPath ונראה יותר כמו ביטוי חילוץ:

תחביר משמעות דוגמה
name גישה לאיבר של אובייקט people
a.b גישה לאיברים מקוננים store.bicycle.color
[0] גישה לאינדקס במערך people[0]
[-1] גישה לאיבר האחרון people[-1]
[0:2] פרוסה, התחלה כוללת וסוף בלעדי people[0:2]
[*] הטלת רשימה people[*].name
[] הטלת שיטוח people[].tags[]
[?condition] הטלת סינון people[?age > 18]
{key: expr} האש בחירה מרובה {name: name, age: age}
[expr, expr] רשימת בחירה מרובה [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 מחזיר מערך: פרוסה מחזירה רשימה, וה-.name שאחריה מוטל אוטומטית על כל איבר ברשימה. זה ההבדל הגדול ביותר בין JMESPath לגישה רגילה לאובייקט.

3. הטלות: להפוך רשימה אחת לאחרת

הטלה היא המושג המרכזי ב-JMESPath. היא פועלת בשני שלבים: להעריך כל איבר ברשימה, ואז לאסוף את התוצאות לרשימה חדשה. איברים שמעריכים ל-null מושלכים אוטומטית.

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

השורה השנייה היא ביטוי הטלה טיפוסי: people[*].{name: name, age: age}. הוא בונה מחדש כל איבר כ-{ "name": ..., "age": ... } ומשליך את שדה ה-city המיותר. לעומת JSONPath, שמחזיר צמתים שאחר כך ממפים בקוד, זה חוסך לולואה אחת.

שני סוגי הטלות שכדאי להבחין ביניהם:

  • [*] שומר על מבנה הרשימה המקורי ומדלג על ערכי null;
  • [] היא הטלת שיטוח שמקפלת קודם רמה אחת של רשימות מקוננות, ומתאימה לביטויים כמו people[].tags[] שצריכים "את כל התגיות של כל האנשים".

4. צינורות ובחירה מרובה

הצינור | פירושו "עצור את ההטלה הנוכחית והתייחס לתוצאה כקלט חדש". השימוש הנפוץ ביותר שלו הוא לקחת אינדקס אחרי הטלה:

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

בלי הצינור, people[*].name[0] מתפרש כנטילת התו הראשון של כל שם, וזה לא מה שרוצים. הצינור הוא הסימן הקל ביותר לפספס והשימושי ביותר ב-JMESPath.

יש שתי צורות של בחירה מרובה:

// 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]

האשי בחירה מרובה טובים לבניית תוצאות עם שמות, ורשימות בחירה מרובה טובות לצריכה לפי מיקום. שניהם יכולים להיות מקוננים בתוך הטלות, אבל שימו לב: בהאש בחירה מרובה, מפתח שערכו null עדיין נשמר, בעוד שהטלה משליכה את כל האיבר ה-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 לבצע אגרגציה פשוטה, בעוד ש-JSONPath מיועד רק לבחירה; סכימה וקיבוץ דורשים בדרך כלל jq או קוד.

6. השוואה צד-לצד עם JSONPath

ממד JSONPath JMESPath
מטרה עיקרית בחירת צמתים המרת נתונים
סימן שורש $ אין; כותבים שמות שדות ישירות
הצומת הנוכחי @ @ (רק בארגומנטים של פונקציות)
מסנן [?(@.age > 18)] [?age > 18]
תו כללי [*] [*] או []
בניית אובייקטים חדשים לא נתמך {name: name}
צינורות לא נתמך |
תקן RFC 9535 מפרט JMESPath

מדריך החלטה במשפט אחד:

  • השתמשו ב-JSONPath כשרק צריך למצוא צמתים שמתאימים לתנאי;
  • השתמשו ב-JMESPath כשצריך לעצב מחדש את התוצאה למה שהפרונט מצפה לו;
  • לא להשתמש באף אחד מהם כשקוראים שדה מוכר אחד; פשוט ניגשים ישירות לתכונה.

אם תוצאת השאילתה חייבת להיכתב בחזרה למסמך, אף אחת מהשפות לא מתאימה. השתמשו ב-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

הפקודה הזו עושה שלושה דברים: היא משטחת שתי רשימות מקוננות עם [], שומרת רק שלושה שדות עם האש בחירה מרובה, ומציגה את התוצאה כטבלה עם --output table. עם JSONPath הייתם צריכים יותר רמות ולא הייתם מקבלים את אפקט "שינוי שם יחד עם צמצום".

צורות נפוצות אחרות:

# Only running instances
aws ec2 describe-instances --query 'Reservations[].Instances[?State.Name==`running`].[InstanceId,PublicIpAddress]'

# The value of the Name tag
aws ec2 describe-instances --query 'Reservations[].Instances[].Tags[?Key==`Name`].Value[]'

שימו לב שהגרשיים האחוריות (backticks) עוטפות ליטרלים, לא מחרוזות. ב-AWS CLI מחרוזות משתמשות בגרשיים בודדות וליטרלים של JSON משתמשים בגרשיים אחוריות. ההבדל הזה הוא אחד הטעויות הנפוצות ביותר של מתחילים.

8. טעויות נפוצות

  • בלבול בין [*] ל-[]: הראשון שומר על הקינון, השני משטח רמה אחת, והמבנים שמתקבלים שונים לחלוטין;
  • שכחת הצינור: people[*].name[0] לוקח את התו הראשון של כל שם, לא את השם הראשון;
  • כתיבת @ בתוך מסנן: מסנני JMESPath משתמשים בשמות שדות ישירות, ולכן [?@.age > 18] שגוי;
  • התייחסות ל-null כמחרוזת ריקה: הטלות משליכות null, אבל האשי בחירה מרובה שומרים על המפתח;
  • שימוש בגרשיים כפולות סביב ליטרלים ב-AWS CLI: ה-shell מרחיב אותן קודם ומשכתב את הביטוי.

עצת דיבוג: אמתו ביטוי על הקלט הקטן ביותר האפשרי לפני שמחילים אותו על נתונים אמיתיים, והוסיפו --output json ב-AWS CLI כדי לראות תוצאות גולמיות. לעריכה ולעיצוב יומיומיים של JSON, שילוב עם עורכי JSON וכלי שורת פקודה הופך את איתור נתיבי השדות להרבה יותר מהיר.

שאלות נפוצות

אפשר להשתמש ב-JMESPath וב-JSONPath יחד?

כן, אבל בדרך כלל זה לא נחוץ. גישה נפוצה היא לצמצם אובייקט קטן עם JMESPath, ואז להשתמש בגישה רגילה לתכונות בקוד. אם באמת צריך לאתר לפי נתיב ואז לשנות, JSONPath קורא ו-JSON Pointer כותב, וזה חלוקת עבודה ברורה יותר.

למה people[*].name מחזיר משהו אחר ממחרוזת יחידה?

כי [*] היא הטלה, והתוצאה היא תמיד רשימה, גם כשיש רק אדם אחד. כדי לקבל ערך יחיד, הוסיפו צינור ואינדקס: people[*].name | [0].

מה קורה ל-null בתוך הטלה?

הטלת רשימה מדלגת אוטומטית על איברים שמעריכים ל-null, ולכן התוצאה עשויה להיות קצרה יותר מהרשימה המקורית. האש בחירה מרובה שומר על המפתח ומשמר את ערך ה-null, וזה משנה כשבנים תגובות API.

JMESPath יכול לבצע אגרגציה וקיבוץ?

הוא יכול לבצע אגרגציה בסיסית עם sum(), max() ו-sort_by(). קיבוץ, joins ופונקציות חלון נמצאים מחוץ לתקן. השאירו ניתוח מורכב ל-jq, ל-SQL או לקוד.

איך מחליטים בין JMESPath ל-JSONPath?

השתמשו ב-JSONPath כשצריך לבחור צמתים לפי נתיב ותנאי ולקבל קבוצת צמתים; השתמשו ב-JMESPath כשצריך לעצב מחדש את התוצאה למה שהפרונט מצפה לו, עם שינוי שמות שדות וצמצום. כשקוראים שדה מוכר אחד, לא להשתמש באף אחד מהם; פשוט ניגשים לתכונה.

כדאי להשתמש בצינור כדי לקחת את הערך המוטל הראשון?

כן. people[*].name היא הטלה, ולכן התוצאה היא תמיד רשימה; בלי צינור, people[*].name[0] לוקח את התו הראשון של כל שם. כתבו people[*].name | [0] כדי לקבל את הערך הראשון.