JSON Toolkit

JMESPath untuk Pemula: Pertanyaan Unjuran yang Mengalahkan JSONPath

Inti pati: JMESPath membentuk semula kumpulan objek dengan lebih langsung daripada JSONPath. Panduan pemula ini merangkumi sintaks, unjuran, paip, fungsi terbina dalam dan penggunaan AWS CLI.

Pemula~9 min bacaanDiterbitkan 2026-10-31Dikemas kini 2026-10-31
Kulit untuk JMESPath untuk Pemula

Intinya: gunakan JSON Pointer untuk mencari mengikut kedudukan, JSONPath untuk menapis atau membuat rekursi, dan JMESPath apabila anda perlu membentuk semula hasil atau mengunjurkannya pada baris arahan; satu medan yang diketahui tidak memerlukan kedua-duanya.

Jika matlamat anda adalah membentuk semula sekumpulan objek kepada bentuk yang lain, JMESPath selalunya lebih langsung daripada JSONPath. Ia tidak mencari nod; ia membina hasil.

1. Apa Itu JMESPath

JMESPath ialah bahasa pertanyaan yang direka khusus untuk JSON. Ia pada mulanya dicipta untuk menapis output AWS CLI dan kemudian tersebar ke banyak bahasa melalui pelaksanaan seperti jmespath.js, jmespath.py, dan go-jmespath. Matlamatnya berbeza daripada JSONPath:

  • JSONPath memberi tumpuan kepada memilih satu set nod mengikut laluan dan syarat, serta memulangkan satu set nod;
  • JMESPath memberi tumpuan kepada mengubah input JSON dan memulangkan nilai dalam sebarang bentuk.

Perbezaan ini menjadikan JMESPath sangat baik untuk unjuran senarai, penamaan semula medan, dan pemangkasan hasil, seperti mengurangkan dua puluh medan daripada respons API kepada tiga medan yang benar-benar diperlukan oleh frontend. Jika anda belum membaca asas JSONPath, mulakan dengan Bahasa Pertanyaan JSONPath dalam Amalan.

2. Sintaks Asas: Daripada Pengenal kepada Indeks

JMESPath menggunakan lebih sedikit simbol daripada JSONPath dan lebih mirip ungkapan pengekstrakan:

Sintaks Maksud Contoh
name Akses anggota objek people
a.b Akses anggota bersarang store.bicycle.color
[0] Akses indeks tatasusunan people[0]
[-1] Akses elemen terakhir people[-1]
[0:2] Hirisan, permulaan inklusif dan penghujung eksklusif people[0:2]
[*] Unjuran senarai people[*].name
[] Unjuran perataan people[].tags[]
[?condition] Unjuran penapis people[?age > 18]
{key: expr} Cincangan pilih berbilang {name: name, age: age}
[expr, expr] Senarai pilih berbilang [name, age]
| Salurkan hasil kiri ke bahagian kanan people[*].age | [0]

Contoh minimum:

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

Perhatikan mengapa people[0:2].name memulangkan tatasusunan: hirisan memulangkan senarai, dan .name berikutnya secara automatik diunjurkan ke atas setiap elemen dalam senarai itu. Ini adalah perbezaan terbesar antara JMESPath dan akses objek biasa.

3. Unjuran: Menukar Satu Senarai Menjadi Senarai Lain

Unjuran ialah konsep teras dalam JMESPath. Ia berfungsi dalam dua langkah: nilaikan setiap elemen senarai, kemudian kumpulkan hasilnya ke dalam senarai baharu. Elemen yang bernilai null digugurkan secara automatik.

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

Baris kedua ialah ungkapan unjuran biasa: people[*].{name: name, age: age}. Ia membina semula setiap elemen sebagai { "name": ..., "age": ... } dan membuang medan city yang berlebihan. Berbanding JSONPath, yang memberikan nod yang kemudian anda petakan dalam kod, ini menjimatkan satu gelung.

Dua jenis unjuran wajar dibezakan:

  • [*] mengekalkan struktur senarai asal dan melangkau nilai null;
  • [] ialah unjuran perataan yang mula-mula meruntuhkan satu tahap senarai bersarang, sesuai untuk ungkapan seperti people[].tags[] yang memerlukan "semua tag semua orang".

4. Paip dan Pilih Berbilang

Paip | bermaksud "hentikan unjuran semasa dan layan hasilnya sebagai input baharu". Penggunaannya yang paling biasa ialah mengambil indeks selepas unjuran:

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

Tanpa paip, people[*].name[0] ditafsirkan sebagai mengambil aksara pertama setiap nama, yang bukan apa yang anda mahu. Paip ialah simbol yang paling mudah terlepas pandang dan paling berguna dalam JMESPath.

Terdapat dua bentuk pilih berbilang:

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

Cincangan pilih berbilang baik untuk membina hasil bernama, manakala senarai pilih berbilang baik untuk penggunaan mengikut kedudukan. Kedua-duanya boleh disarangkan di dalam unjuran, tetapi ambil perhatian: dalam cincangan pilih berbilang, kunci yang nilainya null tetap dikekalkan, sedangkan unjuran menggugurkan keseluruhan elemen null.

5. Fungsi Terbina Dalam

Standard JMESPath mentakrifkan satu set fungsi. Yang biasa termasuk:

Fungsi Tujuan Contoh
length() Dapatkan panjang length(people)
sort() Susun nilai sort(people[*].age)
sort_by() Susun mengikut medan sort_by(people, &age)
max() / min() Maksimum / minimum max(people[*].age)
sum() Jumlah nilai sum(people[*].age)
keys() Dapatkan kunci objek keys(people[0])
contains() Semak kandungan contains(name, "Ali")
to_string() Tukar kepada rentetan to_string(age)

Argumen kedua sort_by ialah ungkapan &, bermaksud "ambil medan ini daripada setiap elemen":

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

Fungsi-fungsi ini membolehkan JMESPath melakukan pengagregatan mudah, sedangkan JSONPath direka hanya untuk pemilihan; penjumlahan dan pengelompokan biasanya memerlukan jq atau kod.

6. Perbandingan Bersebelahan dengan JSONPath

Dimensi JSONPath JMESPath
Matlamat utama Pilih nod Ubah data
Simbol akar $ Tiada; tulis nama medan secara langsung
Nod semasa @ @ (hanya dalam argumen fungsi)
Penapis [?(@.age > 18)] [?age > 18]
Kad liar [*] [*] atau []
Bina objek baharu Tidak disokong {name: name}
Paip Tidak disokong |
Standard RFC 9535 Spesifikasi JMESPath

Panduan keputusan satu ayat:

  • Gunakan JSONPath apabila anda hanya perlu mencari nod yang sepadan dengan syarat;
  • Gunakan JMESPath apabila anda perlu membentuk semula hasil kepada bentuk yang dijangka oleh frontend;
  • Gunakan kedua-duanya sekali pun tidak apabila anda membaca satu medan yang diketahui; cukup akses sifat secara langsung.

Jika hasil pertanyaan mesti ditulis kembali ke dokumen, kedua-dua bahasa ini tidak sesuai. Gunakan JSON Pointer dan patch sebaliknya; lihat JSON Pointer, Patch, dan Merge Patch.

7. JMESPath dalam AWS CLI

Parameter --query AWS CLI ialah JMESPath, iaitu penggunaan paling meluasnya:

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

Arahan ini melakukan tiga perkara: ia meratakan dua senarai bersarang dengan [], mengekalkan hanya tiga medan dengan cincangan pilih berbilang, dan memaparkan hasil sebagai jadual dengan --output table. Dengan JSONPath anda memerlukan lebih banyak tahap dan tidak akan mendapat kesan "namakan semula serta pangkas".

Bentuk biasa yang lain:

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

Perhatikan bahawa tanda belakang mengepit literal, bukan rentetan. Dalam AWS CLI, rentetan menggunakan petikan tunggal dan literal JSON menggunakan tanda belakang. Perbezaan ini ialah salah satu kesilapan pemula yang paling biasa.

8. Kesilapan Biasa

  • Mengelirukan [*] dan []: yang pertama mengekalkan penyarangan, yang kedua meratakan satu tahap, dan struktur yang terhasil sangat berbeza;
  • Terlupa paip: people[*].name[0] mengambil aksara pertama setiap nama, bukan nama pertama;
  • Menulis @ di dalam penapis: penapis JMESPath menggunakan nama medan secara langsung, jadi [?@.age > 18] adalah salah;
  • Menganggap null sebagai rentetan kosong: unjuran menggugurkan null, tetapi cincangan pilih berbilang mengekalkan kunci;
  • Menggunakan petikan berganda pada literal dalam AWS CLI: shell mengembangkannya dahulu dan menulis semula ungkapan itu.

Nasihat penyahpepijatan: sahkan ungkapan pada input sekecil mungkin sebelum menerapkannya pada data sebenar, dan tambah --output json dalam AWS CLI untuk melihat hasil mentah. Untuk penyuntingan dan pemformatan JSON harian, berganding dengan Penyunting JSON dan Alat Baris Arahan menjadikan pencarian laluan medan lebih pantas.

FAQ

Bolehkah JMESPath dan JSONPath digunakan bersama?

Ya, tetapi biasanya tidak perlu. Pendekatan biasa ialah memangkas objek kecil dengan JMESPath, kemudian menggunakan akses sifat biasa dalam kod. Jika anda benar-benar perlu mencari mengikut laluan dan kemudian mengubah, JSONPath membaca dan JSON Pointer menulis, yang merupakan pembahagian tugas yang lebih jelas.

Mengapa people[*].name memulangkan sesuatu selain rentetan tunggal?

Kerana [*] ialah unjuran, dan hasilnya sentiasa senarai, walaupun hanya ada satu orang. Untuk mendapatkan satu nilai, tambah paip dan indeks: people[*].name | [0].

Apa yang berlaku kepada null di dalam unjuran?

Unjuran senarai secara automatik melangkau elemen yang bernilai null, jadi hasilnya mungkin lebih pendek daripada senarai asal. Cincangan pilih berbilang mengekalkan kunci dan memelihara nilai null, yang penting semasa membina respons API.

Bolehkah JMESPath melakukan pengagregatan dan pengelompokan?

Ia boleh melakukan pengagregatan asas dengan sum(), max(), dan sort_by(). Pengelompokan, cantuman, dan fungsi tetingkap berada di luar standard. Serahkan analisis kompleks kepada jq, SQL, atau kod.

Bagaimana saya memutuskan antara JMESPath dan JSONPath?

Gunakan JSONPath apabila anda perlu memilih nod mengikut laluan dan syarat serta menerima satu set nod; gunakan JMESPath apabila anda perlu membentuk semula hasil kepada bentuk yang dijangka oleh frontend, dengan penamaan semula dan pemangkasan medan. Apabila anda membaca satu medan yang diketahui, gunakan kedua-duanya sekali pun tidak; cukup akses sifatnya.

Patutkah saya menggunakan paip untuk mengambil nilai unjuran pertama?

Ya. people[*].name ialah unjuran, jadi hasilnya sentiasa senarai; tanpa paip, people[*].name[0] mengambil aksara pertama setiap nama. Tulis people[*].name | [0] untuk mendapatkan nilai pertama.