JSON Toolkit

JMESPath dla początkujących: zapytania projekcyjne lepsze niż JSONPath

Podsumowanie: JMESPath przekształca partie obiektów bardziej bezpośrednio niż JSONPath. Ten przewodnik dla początkujących omawia składnię, projekcje, potoki, wbudowane funkcje i użycie w AWS CLI.

Początkujący~9 min czytaniaOpublikowano 2026-10-31Zaktualizowano 2026-10-31
Okładka przewodnika JMESPath dla początkujących

Najważniejsze: używaj JSON Pointer do lokalizowania po pozycji, JSONPath do filtrowania lub rekurencji, a JMESPath, gdy musisz przekształcić wynik albo zaprojektować go w wierszu poleceń; pojedyncze znane pole nie potrzebuje żadnego z nich.

Jeśli twoim celem jest przekształcenie partii obiektów w inny kształt, JMESPath jest często bardziej bezpośredni niż JSONPath. Nie szuka węzłów; konstruuje wynik.

1. Czym jest JMESPath

JMESPath to język zapytań zaprojektowany specjalnie dla JSON. Powstał pierwotnie do filtrowania wyjścia AWS CLI, a później rozprzestrzenił się na wiele języków przez implementacje takie jak jmespath.js, jmespath.py i go-jmespath. Jego cel różni się od JSONPath:

  • JSONPath skupia się na wybieraniu zbioru węzłów po ścieżce i warunku i zwraca zbiór węzłów;
  • JMESPath skupia się na przekształcaniu wejściowego JSON-a i zwraca wartość o dowolnym kształcie.

Ta różnica czyni JMESPath szczególnie dobrym do projekcji list, zmiany nazw pól i przycinania wyników, na przykład redukcji dwudziestu pól z odpowiedzi API do trzech pól, których frontend naprawdę potrzebuje. Jeśli nie czytałeś jeszcze podstaw JSONPath, zacznij od Języka zapytań JSONPath w praktyce.

2. Podstawowa składnia: od identyfikatorów do indeksów

JMESPath używa mniej symboli niż JSONPath i czyta się bardziej jak wyrażenie ekstrakcji:

Składnia Znaczenie Przykład
name Dostęp do składowej obiektu people
a.b Dostęp do zagnieżdżonych składowych store.bicycle.color
[0] Dostęp do indeksu tablicy people[0]
[-1] Dostęp do ostatniego elementu people[-1]
[0:2] Wycinek, początek włącznie, koniec wyłącznie people[0:2]
[*] Projekcja listy people[*].name
[] Projekcja spłaszczająca people[].tags[]
[?condition] Projekcja filtrująca people[?age > 18]
{key: expr} Wieloselekcyjny hash {name: name, age: age}
[expr, expr] Wieloselekcyjna lista [name, age]
| Przekazanie wyniku lewej strony do prawej people[*].age | [0]

Minimalny przykład:

{
  "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"]

Zauważ, dlaczego people[0:2].name zwraca tablicę: wycinek zwraca listę, a następujące .name jest automatycznie projektowane na każdy element tej listy. To największa różnica między JMESPath a zwykłym dostępem do obiektu.

3. Projekcje: zamiana jednej listy w drugą

Projekcja to kluczowe pojęcie w JMESPath. Działa w dwóch krokach: oceń każdy element listy, a następnie zbierz wyniki w nową listę. Elementy, które oceniają się do null, są automatycznie odrzucane.

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

Druga linia to typowe wyrażenie projekcyjne: people[*].{name: name, age: age}. Odbudowuje każdy element jako { "name": ..., "age": ... } i odrzuca dodatkowe pole city. W porównaniu z JSONPath, który daje węzły, które potem mapujesz w kodzie, to oszczędza pętlę.

Warto rozróżnić dwa rodzaje projekcji:

  • [*] zachowuje oryginalną strukturę listy i pomija wartości null;
  • [] to projekcja spłaszczająca, która najpierw zwija jeden poziom zagnieżdżonych list, co pasuje do wyrażeń takich jak people[].tags[], potrzebujących „wszystkich tagów wszystkich osób”.

4. Potoki i wieloselekcja

Potok | znaczy „zatrzymaj obecną projekcję i potraktuj wynik jako nowe wejście”. Jego najczęstsze użycie to wzięcie indeksu po projekcji:

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

Bez potoku people[*].name[0] jest interpretowane jako wzięcie pierwszego znaku każdej nazwy, co nie jest tym, czego chcesz. Potok to najbardziej przeoczany i najbardziej użyteczny symbol w JMESPath.

Istnieją dwie formy wieloselekcji:

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

Wieloselekcyjne hashe są dobre do konstruowania nazwanych wyników, a wieloselekcyjne listy do konsumpcji pozycyjnej. Oba można zagnieżdżać w projekcjach, ale uwaga: w wieloselekcyjnym hashu klucz o wartości null nadal jest zachowywany, podczas gdy projekcja odrzuca cały element null.

5. Wbudowane funkcje

Standard JMESPath definiuje zestaw funkcji. Częste z nich to:

Funkcja Cel Przykład
length() Długość length(people)
sort() Sortowanie wartości sort(people[*].age)
sort_by() Sortowanie po polu sort_by(people, &age)
max() / min() Maksimum / minimum max(people[*].age)
sum() Suma wartości sum(people[*].age)
keys() Klucze obiektu keys(people[0])
contains() Sprawdzenie zawierania contains(name, "Ali")
to_string() Konwersja do łańcucha to_string(age)

Drugi argument sort_by to wyrażenie &, znaczące „weź to pole z każdego elementu”:

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

Te funkcje pozwalają JMESPath wykonywać prostą agregację, podczas gdy JSONPath jest zaprojektowany tylko do selekcji; sumowanie i grupowanie zwykle wymagają jq lub kodu.

6. Porównanie obok siebie z JSONPath

Wymiar JSONPath JMESPath
Główny cel Wybór węzłów Przekształcanie danych
Symbol korzenia $ Brak; pisz nazwy pól bezpośrednio
Obecny węzeł @ @ (tylko w argumentach funkcji)
Filtr [?(@.age > 18)] [?age > 18]
Symbol wieloznaczny [*] [*] lub []
Konstruowanie nowych obiektów Niewspierane {name: name}
Potoki Niewspierane |
Standard RFC 9535 Specyfikacja JMESPath

Przewodnik decyzyjny w jednym zdaniu:

  • Użyj JSONPath, gdy potrzebujesz tylko znaleźć węzły pasujące do warunku;
  • Użyj JMESPath, gdy musisz przekształcić wynik w to, czego oczekuje frontend;
  • Nie używaj żadnego z nich, gdy czytasz jedno znane pole; po prostu uzyskaj dostęp do właściwości bezpośrednio.

Jeśli wynik zapytania musi zostać zapisany z powrotem do dokumentu, żaden język nie pasuje. Zamiast tego użyj JSON Pointer i patchy; zobacz JSON Pointer, Patch i Merge Patch.

7. JMESPath w AWS CLI

Parametr --query w AWS CLI to JMESPath, co jest jego najszerzej rozpowszechnionym zastosowaniem:

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

To polecenie robi trzy rzeczy: spłaszcza dwie zagnieżdżone listy przez [], zachowuje tylko trzy pola przez wieloselekcyjny hash i renderuje wynik jako tabelę przez --output table. W JSONPath potrzebowałbyś więcej poziomów i nie dostałbyś efektu „zmiana nazwy plus przycięcie”.

Inne częste formy:

# 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[]'

Zauważ, że backticki otaczają literały, a nie łańcuchy. W AWS CLI łańcuchy używają pojedynczych cudzysłowów, a literały JSON używają backticków. Ta różnica to jeden z najczęstszych błędów początkujących.

8. Częste błędy

  • Mylenie [*] i []: pierwszy zachowuje zagnieżdżenie, drugi spłaszcza jeden poziom, a wynikowe struktury są zupełnie różne;
  • Zapominanie potoku: people[*].name[0] bierze pierwszy znak każdej nazwy, a nie pierwszą nazwę;
  • Pisanie @ wewnątrz filtra: filtry JMESPath używają nazw pól bezpośrednio, więc [?@.age > 18] jest błędne;
  • Traktowanie null jak pustego łańcucha: projekcje odrzucają null, ale wieloselekcyjne hashe zachowują klucz;
  • Używanie podwójnych cudzysłowów wokół literałów w AWS CLI: powłoka najpierw je rozwija i przepisuje wyrażenie.

Rada debugowania: zwaliduj wyrażenie na najmniejszym możliwym wejściu, zanim zastosujesz je do prawdziwych danych, i dodaj --output json w AWS CLI, aby zobaczyć surowe wyniki. Do codziennej edycji i formatowania JSON połączenie z Edytorami JSON i narzędziami wiersza poleceń znacznie przyspiesza lokalizowanie ścieżek pól.

FAQ

Czy JMESPath i JSONPath można używać razem?

Tak, ale zwykle jest to niepotrzebne. Częste podejście to przycięcie małego obiektu przez JMESPath, a potem zwykły dostęp do właściwości w kodzie. Jeśli naprawdę musisz lokalizować po ścieżce i modyfikować, JSONPath czyta, a JSON Pointer pisze, co jest jaśniejszym podziałem pracy.

Dlaczego people[*].name zwraca coś innego niż pojedynczy łańcuch?

Bo [*] to projekcja, a wynik zawsze jest listą, nawet gdy jest tylko jedna osoba. Aby uzyskać pojedynczą wartość, dodaj potok i indeks: people[*].name | [0].

Co się dzieje z null wewnątrz projekcji?

Projekcja listy automatycznie pomija elementy, które oceniają się do null, więc wynik może być krótszy niż oryginalna lista. Wieloselekcyjny hash zachowuje klucz i wartość null, co ma znaczenie przy konstruowaniu odpowiedzi API.

Czy JMESPath potrafi agregować i grupować?

Potrafi prostą agregację przez sum(), max() i sort_by(). Grupowanie, łączenia i funkcje okna są poza standardem. Złożoną analizę zostaw jq, SQL lub kodowi.

Jak zdecydować między JMESPath a JSONPath?

Użyj JSONPath, gdy musisz wybierać węzły po ścieżce i warunku i otrzymać zbiór węzłów; użyj JMESPath, gdy musisz przekształcić wynik w to, czego oczekuje frontend, ze zmianą nazw i przycinaniem pól. Gdy czytasz jedno znane pole, nie używaj żadnego z nich; po prostu uzyskaj dostęp do właściwości.

Czy użyć potoku, aby wziąć pierwszą zaprojektowaną wartość?

Tak. people[*].name to projekcja, więc wynik zawsze jest listą; bez potoku people[*].name[0] bierze pierwszy znak każdej nazwy. Napisz people[*].name | [0], aby uzyskać pierwszą wartość.