JMESPath pro začátečníky: projekce, které porazí JSONPath
Shrnutí: JMESPath přetváří dávky objektů přímočařeji než JSONPath. Tento průvodce pro začátečníky pokrývá syntaxi, projekce, pipes, vestavěné funkce a použití v AWS CLI.

Stručně: JSON Pointer použijte k lokalizaci podle pozice, JSONPath k filtrování nebo rekurzi a JMESPath, když potřebujete výsledek přetvořit nebo ho projektovat na příkazovém řádku; jedno známé pole nepotřebuje ani jedno.
Pokud je vaším cílem přetvořit dávku objektů do jiného tvaru, JMESPath je často přímočařejší než JSONPath. Nehraje uzly; konstruuje výsledek.
1. Co JMESPath je
JMESPath je dotazovací jazyk navržený speciálně pro JSON. Původně vznikl pro filtrování výstupu AWS CLI a později se rozšířil do mnoha jazyků přes implementace jako jmespath.js, jmespath.py a go-jmespath. Jeho cíl se liší od JSONPath:
- JSONPath se soustředí na výběr množiny uzlů podle cesty a podmínky a vrací množinu uzlů;
- JMESPath se soustředí na transformaci vstupního JSON a vrací hodnotu libovolného tvaru.
Tento rozdíl činí JMESPath obzvlášť dobrým pro projekce seznamů, přejmenování polí a ořez výsledků, například zredukování dvaceti polí z odpovědi API na tři pole, která frontend skutečně potřebuje. Pokud jste ještě nečetli základy JSONPath, začněte s Dotazovací jazyk JSONPath v praxi.
2. Základní syntaxe: od identifikátorů k indexům
JMESPath používá méně symbolů než JSONPath a čte se spíš jako extrakční výraz:
| Syntaxe | Význam | Příklad |
|---|---|---|
name |
Přístup ke členu objektu | people |
a.b |
Přístup k vnořeným členům | store.bicycle.color |
[0] |
Přístup k indexu pole | people[0] |
[-1] |
Přístup k poslednímu prvku | people[-1] |
[0:2] |
Slice, včetně začátku a bez konce | people[0:2] |
[*] |
Projekce seznamu | people[*].name |
[] |
Zplošťující projekce | people[].tags[] |
[?condition] |
Filtrační projekce | people[?age > 18] |
{key: expr} |
Vícenásobný výběr do hash | {name: name, age: age} |
[expr, expr] |
Vícenásobný výběr do seznamu | [name, age] |
| |
Předá levý výsledek do pravé strany | people[*].age | [0] |
Minimální příklad:
{
"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"]
Všimněte si, proč people[0:2].name vrací pole: slice vrací seznam a následující .name se automaticky projektuje přes každý prvek toho seznamu. To je největší rozdíl mezi JMESPath a obyčejným přístupem k objektu.
3. Projekce: přeměna jednoho seznamu na jiný
Projekce je klíčový koncept JMESPath. Funguje ve dvou krocích: vyhodnotí každý prvek seznamu a poté výsledky shromáždí do nového seznamu. Prvky, které se vyhodnotí jako null, jsou automaticky zahozeny.
people[*].name // ["Alice", "Bob"]
people[*].{name: name, age: age} // seznam objektů
people[?age > 18].name // ["Alice"]
Druhý řádek je typický projekční výraz: people[*].{name: name, age: age}. Přestaví každý prvek jako { "name": ..., "age": ... } a zahodí nadbytečné pole city. Ve srovnání s JSONPath, který vám dá uzly, jež pak mapujete v kódu, to ušetří jednu smyčku.
Dva druhy projekcí stojí za rozlišení:
[*]zachovává původní strukturu seznamu a přeskakuje nulové hodnoty;[]je zplošťující projekce, která nejprve slisuje jednu úroveň vnořených seznamů, což se hodí pro výrazy jakopeople[].tags[], které potřebují „všechny tagy všech lidí“.
4. Pipes a vícenásobný výběr
Pipe | znamená „zastav aktuální projekci a považuj výsledek za nový vstup“. Jeho nejčastější použití je vzít index po projekci:
people[*].name | [0] → "Alice"
people[*].age | sort(@) | [-1] → maximální věk
Bez pipe se people[*].name[0] interpretuje jako první znak každého jména, což není to, co chcete. Pipe je nejsnadněji přehlédnutelný a nejužitečnější symbol v JMESPath.
Existují dvě formy vícenásobného výběru:
// Vícenásobný výběr do hash: výsledkem je objekt
people[0].{name: name, age: age}
// Vícenásobný výběr do seznamu: výsledkem je pole
people[0].[name, age]
Vícenásobné hashe se hodí pro konstrukci pojmenovaných výsledků, zatímco vícenásobné seznamy pro poziční konzumaci. Oba lze vnořit do projekcí, ale pozor: ve vícenásobném hashi zůstává klíč, jehož hodnota je null, zatímco projekce zahodí celý null prvek.
5. Vestavěné funkce
Standard JMESPath definuje sadu funkcí. Běžné zahrnují:
| Funkce | Účel | Příklad |
|---|---|---|
length() |
Získat délku | length(people) |
sort() |
Seřadit hodnoty | sort(people[*].age) |
sort_by() |
Seřadit podle pole | sort_by(people, &age) |
max() / min() |
Maximum / minimum | max(people[*].age) |
sum() |
Součet hodnot | sum(people[*].age) |
keys() |
Získat klíče objektu | keys(people[0]) |
contains() |
Ověřit obsažení | contains(name, "Ali") |
to_string() |
Převést na řetězec | to_string(age) |
Druhý argument sort_by je výraz &, který znamená „vezmi toto pole z každého prvku“:
sort_by(people, &age)[*].name
Tyto funkce nechávají JMESPath provádět jednoduchou agregaci, zatímco JSONPath je navržen jen pro výběr; sčítání a seskupování obvykle vyžadují jq nebo kód.
6. Srovnání vedle sebe s JSONPath
| Dimenze | JSONPath | JMESPath |
|---|---|---|
| Primární cíl | Vybrat uzly | Transformovat data |
| Kořenový symbol | $ |
Žádný; pište názvy polí přímo |
| Aktuální uzel | @ |
@ (jen v argumentech funkcí) |
| Filtr | [?(@.age > 18)] |
[?age > 18] |
| Zástupný znak | [*] |
[*] nebo [] |
| Konstrukce nových objektů | Nepodporováno | {name: name} |
| Pipes | Nepodporováno | | |
| Standard | RFC 9535 | JMESPath Specification |
Rozhodovací vodítko v jedné větě:
- JSONPath použijte, když potřebujete jen najít uzly odpovídající podmínce;
- JMESPath použijte, když potřebujete výsledek přetvořit do podoby, kterou frontend očekává;
- Nepoužívejte ani jedno, když čtete jedno známé pole; prostě přistupte k vlastnosti přímo.
Pokud výsledek dotazu musí být zapsán zpět do dokumentu, ani jeden jazyk není vhodný. Použijte JSON Pointer a patche; viz JSON Pointer, Patch a Merge Patch.
7. JMESPath v AWS CLI
Parametr --query v AWS CLI je JMESPath, což je jeho nejrozšířenější případ použití:
aws ec2 describe-instances \
--query 'Reservations[].Instances[].{Id: InstanceId, State: State.Name, Type: InstanceType}' \
--output table
Tento příkaz dělá tři věci: zplošťuje dva vnořené seznamy pomocí [], udrží jen tři pole pomocí vícenásobného hashe a vykreslí výsledek jako tabulku pomocí --output table. S JSONPath byste potřebovali více úrovní a nezískali byste efekt „přejmenovat a oříznout“.
Další běžné formy:
# Jen běžící instance
aws ec2 describe-instances --query 'Reservations[].Instances[?State.Name==`running`].[InstanceId,PublicIpAddress]'
# Hodnota tagu Name
aws ec2 describe-instances --query 'Reservations[].Instances[].Tags[?Key==`Name`].Value[]'
Pozor, zpětné apostrofy obklopují literály, nikoli řetězce. V AWS CLI řetězce používají jednoduché uvozovky a JSON literály zpětné apostrofy. Tento rozdíl je jednou z nejběžnějších začátečnických chyb.
8. Běžné chyby
- Záměna
[*]a[]: první zachovává vnoření, druhé zplošťuje jednu úroveň a výsledné struktury jsou zcela odlišné; - Zapomenutá pipe:
people[*].name[0]bere první znak každého jména, nikoli první jméno; - Psaní
@uvnitř filtru: filtry JMESPath používají názvy polí přímo, takže[?@.age > 18]je špatně; - Považování
nullza prázdný řetězec: projekce zahazujínull, ale vícenásobné hashe klíč zachovávají; - Používání dvojitých uvozovek kolem literálů v AWS CLI: shell je nejprve expanduje a výraz přepíše.
Rada pro ladění: výraz validujte na nejmenším možném vstupu, než ho použijete na skutečná data, a v AWS CLI přidejte --output json, abyste viděli surové výsledky. Pro každodenní úpravy a formátování JSON je kombinace s Editory JSON a nástroji příkazového řádku mnohem rychlejší při lokalizaci cest polí.
Časté dotazy
Lze JMESPath a JSONPath použít společně?
Ano, ale obvykle to není nutné. Běžný přístup je oříznout malý objekt pomocí JMESPath a poté použít obyčejný přístup k vlastnostem v kódu. Pokud skutečně potřebujete lokalizovat podle cesty a poté upravit, JSONPath čte a JSON Pointer zapisuje, což je jasnější rozdělení práce.
Proč people[*].name nevrací jediný řetězec?
Protože [*] je projekce a výsledkem je vždy seznam, i když je tam jen jedna osoba. Pro jedinou hodnotu přidejte pipe a index: people[*].name | [0].
Co se stane s null uvnitř projekce?
Projekce seznamu automaticky přeskakuje prvky, které se vyhodnotí jako null, takže výsledek může být kratší než původní seznam. Vícenásobný hash klíč zachová a hodnotu null ponechá, což záleží při konstrukci odpovědí API.
Umí JMESPath agregaci a seskupování?
Umí základní agregaci pomocí sum(), max() a sort_by(). Seskupování, joins a window funkce jsou mimo standard. Složitou analýzu nechte na jq, SQL nebo kódu.
Jak se rozhodnout mezi JMESPath a JSONPath?
JSONPath použijte, když potřebujete vybrat uzly podle cesty a podmínky a dostat množinu uzlů; JMESPath použijte, když potřebujete výsledek přetvořit do podoby, kterou frontend očekává, s přejmenováním a ořezem polí. Když čtete jedno známé pole, nepoužívejte ani jedno; prostě přistupte k vlastnosti.
Mám použít pipe k získání první projektované hodnoty?
Ano. people[*].name je projekce, takže výsledkem je vždy seznam; bez pipe people[*].name[0] bere první znak každého jména. Pro první hodnotu napište people[*].name | [0].