JSON Toolkit

JMESPath für Einsteiger: Projektionsabfragen, die JSONPath schlagen

Fazit: JMESPath formt Stapel von Objekten direkter um als JSONPath. Dieser Einsteigerleitfaden behandelt Syntax, Projektionen, Pipes, eingebaute Funktionen und die Nutzung in der AWS CLI.

Einsteiger~9 Min. LesezeitVeröffentlicht 2026-10-31Aktualisiert 2026-10-31
Titelbild für JMESPath für Einsteiger

Kurz gesagt: JSON Pointer zum Lokalisieren nach Position, JSONPath zum Filtern oder Rekursieren und JMESPath, wenn Sie das Ergebnis umformen oder auf der Kommandozeile projizieren müssen; ein einzelnes bekanntes Feld braucht keines davon.

Wenn Ihr Ziel ist, einen Stapel von Objekten in eine andere Form zu bringen, ist JMESPath oft direkter als JSONPath. Es sucht keine Knoten; es konstruiert ein Ergebnis.

1. Was JMESPath ist

JMESPath ist eine Abfragesprache, die speziell für JSON entworfen wurde. Sie entstand ursprünglich zum Filtern von AWS-CLI-Ausgaben und verbreitete sich später über Implementierungen wie jmespath.js, jmespath.py und go-jmespath in viele Sprachen. Ihr Ziel unterscheidet sich von JSONPath:

  • JSONPath konzentriert sich darauf, eine Menge von Knoten nach Pfad und Bedingung auszuwählen, und gibt eine Knotenmenge zurück;
  • JMESPath konzentriert sich darauf, die Eingabe-JSON zu transformieren, und gibt einen Wert beliebiger Form zurück.

Dieser Unterschied macht JMESPath besonders gut für Listenprojektionen, Feldumbenennung und Ergebnisbeschneidung, etwa zwanzig Felder einer API-Antwort auf die drei Felder zu reduzieren, die das Frontend tatsächlich braucht. Haben Sie die Grundlagen von JSONPath noch nicht gelesen, beginnen Sie mit Die JSONPath-Abfragesprache in der Praxis.

2. Grundsyntax: von Identifikatoren zu Indizes

JMESPath verwendet weniger Symbole als JSONPath und liest sich eher wie ein Extraktionsausdruck:

Syntax Bedeutung Beispiel
name Auf ein Objektmitglied zugreifen people
a.b Auf verschachtelte Mitglieder zugreifen store.bicycle.color
[0] Auf einen Array-Index zugreifen people[0]
[-1] Auf das letzte Element zugreifen people[-1]
[0:2] Slice, inklusiver Anfang und exklusives Ende people[0:2]
[*] Listenprojektion people[*].name
[] Flatten-Projektion people[].tags[]
[?condition] Filterprojektion people[?age > 18]
{key: expr} Multi-Select-Hash {name: name, age: age}
[expr, expr] Multi-Select-Liste [name, age]
| Das linke Ergebnis in die rechte Seite leiten people[*].age | [0]

Ein Minimalbeispiel:

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

Beachten Sie, warum people[0:2].name ein Array zurückgibt: Ein Slice liefert eine Liste, und das folgende .name wird automatisch über jedes Element dieser Liste projiziert. Das ist der größte Unterschied zwischen JMESPath und gewöhnlichem Objektzugriff.

3. Projektionen: Eine Liste in eine andere verwandeln

Eine Projektion ist das Kernkonzept in JMESPath. Sie arbeitet in zwei Schritten: jedes Element einer Liste auswerten und dann die Ergebnisse in einer neuen Liste sammeln. Elemente, die zu null auswerten, werden automatisch verworfen.

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

Die zweite Zeile ist ein typischer Projektionsausdruck: people[*].{name: name, age: age}. Er baut jedes Element als { "name": ..., "age": ... } neu auf und verwirft das zusätzliche Feld city. Verglichen mit JSONPath, das Knoten liefert, die Sie dann im Code abbilden, spart das eine Schleife.

Zwei Arten von Projektionen sind zu unterscheiden:

  • [*] bewahrt die ursprüngliche Listenstruktur und überspringt null-Werte;
  • [] ist eine Flatten-Projektion, die zuerst eine Ebene verschachtelter Listen kollabiert, was zu Ausdrücken wie people[].tags[] passt, die „alle Tags aller Personen“ brauchen.

4. Pipes und Multi-Select

Die Pipe | bedeutet „die aktuelle Projektion beenden und das Ergebnis als neue Eingabe behandeln“. Ihre häufigste Verwendung ist, nach einer Projektion einen Index zu nehmen:

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

Ohne Pipe wird people[*].name[0] als „das erste Zeichen jedes Namens“ interpretiert, was Sie nicht wollen. Die Pipe ist das am leichtesten übersehene und nützlichste Symbol in JMESPath.

Es gibt zwei Formen von 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-Hashes eignen sich zum Konstruieren benannter Ergebnisse, Multi-Select-Listen für positionsbasierten Verbrauch. Beide lassen sich in Projektionen verschachteln, beachten Sie aber: In einem Multi-Select-Hash bleibt ein Schlüssel mit dem Wert null erhalten, während eine Projektion das gesamte null-Element verwirft.

5. Eingebaute Funktionen

Die JMESPath-Spezifikation definiert eine Reihe von Funktionen. Häufige sind:

Funktion Zweck Beispiel
length() Länge holen length(people)
sort() Werte sortieren sort(people[*].age)
sort_by() Nach einem Feld sortieren sort_by(people, &age)
max() / min() Maximum / Minimum max(people[*].age)
sum() Werte summieren sum(people[*].age)
keys() Objektschlüssel holen keys(people[0])
contains() Enthaltensein prüfen contains(name, "Ali")
to_string() In String umwandeln to_string(age)

Das zweite Argument von sort_by ist ein &-Ausdruck, der „dieses Feld aus jedem Element nehmen“ bedeutet:

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

Diese Funktionen lassen JMESPath einfache Aggregation ausführen, während JSONPath nur für die Auswahl entworfen ist; Summieren und Gruppieren brauchen meist jq oder Code.

6. Ein direkter Vergleich mit JSONPath

Dimension JSONPath JMESPath
Hauptziel Knoten auswählen Daten transformieren
Wurzelsymbol $ Keines; Feldnamen direkt schreiben
Aktueller Knoten @ @ (nur in Funktionsargumenten)
Filter [?(@.age > 18)] [?age > 18]
Platzhalter [*] [*] oder []
Neue Objekte konstruieren Nicht unterstützt {name: name}
Pipes Nicht unterstützt |
Standard RFC 9535 JMESPath-Spezifikation

Ein Entscheidungsleitfaden in einem Satz:

  • Verwenden Sie JSONPath, wenn Sie nur Knoten finden müssen, die einer Bedingung entsprechen;
  • Verwenden Sie JMESPath, wenn Sie das Ergebnis in die vom Frontend erwartete Form umformen müssen;
  • Verwenden Sie keines von beiden, wenn Sie ein bekanntes Feld lesen; greifen Sie einfach direkt auf die Property zu.

Muss das Abfrageergebnis in das Dokument zurückgeschrieben werden, ist keine der beiden Sprachen geeignet. Verwenden Sie stattdessen JSON Pointer und Patches; siehe JSON Pointer, Patch und Merge Patch.

7. JMESPath in der AWS CLI

Der --query-Parameter der AWS CLI ist JMESPath, was ihr am weitesten verbreiteter Anwendungsfall ist:

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

Dieser Befehl tut drei Dinge: Er flacht zwei verschachtelte Listen mit [] ab, behält nur drei Felder mit einem Multi-Select-Hash und rendert das Ergebnis mit --output table als Tabelle. Mit JSONPath bräuchten Sie mehr Ebenen und bekämen nicht den Effekt „umbenennen plus beschneiden“.

Weitere häufige Formen:

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

Beachten Sie, dass Backticks Literale einschließen, keine Strings. In der AWS CLI verwenden Strings einfache Anführungszeichen und JSON-Literale Backticks. Dieser Unterschied ist einer der häufigsten Anfängerfehler.

8. Häufige Fehler

  • [*] und [] verwechseln: Ersteres bewahrt die Verschachtelung, Letzteres flacht eine Ebene ab, und die resultierenden Strukturen sind völlig verschieden;
  • Die Pipe vergessen: people[*].name[0] nimmt das erste Zeichen jedes Namens, nicht den ersten Namen;
  • @ innerhalb eines Filters schreiben: JMESPath-Filter verwenden Feldnamen direkt, [?@.age > 18] ist also falsch;
  • null als leeren String behandeln: Projektionen verwerfen null, Multi-Select-Hashes behalten den Schlüssel;
  • Doppelte Anführungszeichen um Literale in der AWS CLI verwenden: Die Shell expandiert sie zuerst und schreibt den Ausdruck um.

Debugging-Rat: Validieren Sie einen Ausdruck mit der kleinstmöglichen Eingabe, bevor Sie ihn auf echte Daten anwenden, und ergänzen Sie in der AWS CLI --output json, um Rohresultate zu sehen. Für alltägliches JSON-Bearbeiten und -Formatieren beschleunigt die Kombination mit JSON-Editoren und Kommandozeilenwerkzeugen das Lokalisieren von Feldpfaden erheblich.

FAQ

Können JMESPath und JSONPath zusammen verwendet werden?

Ja, aber meist ist es unnötig. Ein üblicher Ansatz ist, ein kleines Objekt mit JMESPath zu beschneiden und dann im Code gewöhnlichen Property-Zugriff zu verwenden. Müssen Sie wirklich nach Pfad lokalisieren und dann ändern, liest JSONPath und schreibt JSON Pointer, eine klarere Arbeitsteilung.

Warum gibt people[*].name etwas anderes als einen einzelnen String zurück?

Weil [*] eine Projektion ist und das Ergebnis immer eine Liste ist, selbst wenn es nur eine Person gibt. Um einen einzelnen Wert zu erhalten, ergänzen Sie eine Pipe und einen Index: people[*].name | [0].

Was passiert mit null innerhalb einer Projektion?

Eine Listenprojektion überspringt automatisch Elemente, die zu null auswerten, das Ergebnis kann also kürzer als die ursprüngliche Liste sein. Ein Multi-Select-Hash behält den Schlüssel und bewahrt den null-Wert, was beim Konstruieren von API-Antworten zählt.

Kann JMESPath Aggregation und Gruppierung?

Es kann mit sum(), max() und sort_by() einfache Aggregation. Gruppierung, Joins und Fensterfunktionen liegen außerhalb der Spezifikation. Überlassen Sie komplexe Analyse jq, SQL oder Code.

Wie entscheide ich zwischen JMESPath und JSONPath?

Verwenden Sie JSONPath, wenn Sie Knoten nach Pfad und Bedingung auswählen und eine Knotenmenge erhalten müssen; verwenden Sie JMESPath, wenn Sie das Ergebnis in die vom Frontend erwartete Form umformen müssen, mit Feldumbenennung und Beschneidung. Lesen Sie ein bekanntes Feld, verwenden Sie keines von beiden; greifen Sie einfach auf die Property zu.

Sollte ich eine Pipe verwenden, um den ersten projizierten Wert zu nehmen?

Ja. people[*].name ist eine Projektion, das Ergebnis ist also immer eine Liste; ohne Pipe nimmt people[*].name[0] das erste Zeichen jedes Namens. Schreiben Sie people[*].name | [0], um den ersten Wert zu erhalten.