TL;DR
SELECT json_agg(t) FROM t
untuk array objek JSON, dan
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)
FROM t
untuk objek array JSON.
Daftar objek
Bagian ini menjelaskan cara menghasilkan larik objek JSON, dengan setiap baris dikonversi menjadi satu objek. Hasilnya terlihat seperti ini:
[{"a":1,"b":"value1"},{"a":2,"b":"value2"},{"a":3,"b":"value3"}]
9.3 dan lebih tinggi
json_agg
fungsi menghasilkan hasil ini di luar kotak. Secara otomatis mengetahui cara mengubah inputnya menjadi JSON dan menggabungkannya menjadi array.
SELECT json_agg(t) FROM t
Tidak ada jsonb
(diperkenalkan pada 9.4) versi json_agg
. Anda dapat menggabungkan baris menjadi sebuah array dan kemudian mengonversinya:
SELECT to_jsonb(array_agg(t)) FROM t
atau gabungkan json_agg
dengan pemeran:
SELECT json_agg(t)::jsonb FROM t
Pengujian saya menunjukkan bahwa menggabungkannya ke dalam array terlebih dahulu sedikit lebih cepat. Saya menduga ini karena para pemain harus mengurai seluruh hasil JSON.
9.2
9.2 tidak memiliki json_agg
atau to_json
fungsi, jadi Anda perlu menggunakan array_to_json
yang lebih lama :
SELECT array_to_json(array_agg(t)) FROM t
Anda dapat secara opsional menyertakan row_to_json
panggil dalam kueri:
SELECT array_to_json(array_agg(row_to_json(t))) FROM t
Ini mengonversi setiap baris menjadi objek JSON, menggabungkan objek JSON sebagai larik, lalu mengonversi larik menjadi larik JSON.
Saya tidak dapat melihat perbedaan performa yang signifikan di antara keduanya.
Objek daftar
Bagian ini menjelaskan cara menghasilkan objek JSON, dengan setiap kunci menjadi kolom dalam tabel dan setiap nilai menjadi larik dari nilai kolom. Hasilnya seperti ini:
{"a":[1,2,3], "b":["value1","value2","value3"]}
9.5 dan lebih tinggi
Kita dapat memanfaatkan json_build_object
fungsi:
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)
FROM t
Anda juga dapat menggabungkan kolom, membuat satu baris, lalu mengubahnya menjadi objek:
SELECT to_json(r)
FROM (
SELECT
json_agg(t.a) AS a,
json_agg(t.b) AS b
FROM t
) r
Perhatikan bahwa aliasing array mutlak diperlukan untuk memastikan bahwa objek memiliki nama yang diinginkan.
Mana yang lebih jelas adalah masalah pendapat. Jika menggunakan json_build_object
fungsi, saya sangat menyarankan menempatkan satu pasangan kunci/nilai pada baris untuk meningkatkan keterbacaan.
Anda juga dapat menggunakan array_agg
sebagai pengganti json_agg
, tetapi pengujian saya menunjukkan bahwa json_agg
sedikit lebih cepat.
Tidak ada jsonb
versi json_build_object
fungsi. Anda dapat menggabungkan menjadi satu baris dan mengonversi:
SELECT to_jsonb(r)
FROM (
SELECT
array_agg(t.a) AS a,
array_agg(t.b) AS b
FROM t
) r
Tidak seperti kueri lain untuk hasil seperti ini, array_agg
tampaknya sedikit lebih cepat saat menggunakan to_jsonb
. Saya menduga ini karena penguraian overhead dan memvalidasi hasil JSON dari json_agg
.
Atau Anda dapat menggunakan pemeran eksplisit:
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)::jsonb
FROM t
to_jsonb
versi memungkinkan Anda untuk menghindari pemeran dan lebih cepat, menurut pengujian saya; sekali lagi, saya menduga ini karena overhead parsing dan validasi hasilnya.
9,4 dan 9,3
json_build_object
function baru untuk 9.5, jadi Anda harus menggabungkan dan mengonversi ke objek di versi sebelumnya:
SELECT to_json(r)
FROM (
SELECT
json_agg(t.a) AS a,
json_agg(t.b) AS b
FROM t
) r
atau
SELECT to_jsonb(r)
FROM (
SELECT
array_agg(t.a) AS a,
array_agg(t.b) AS b
FROM t
) r
tergantung pada apakah Anda ingin json
atau jsonb
.
(9.3 tidak memiliki jsonb
.)
9.2
Di 9.2, bahkan tidak to_json
ada. Anda harus menggunakan row_to_json
:
SELECT row_to_json(r)
FROM (
SELECT
array_agg(t.a) AS a,
array_agg(t.b) AS b
FROM t
) r
Dokumentasi
Temukan dokumentasi untuk fungsi JSON di fungsi JSON.
json_agg
ada di halaman fungsi agregat.
Desain
Jika kinerja penting, pastikan Anda membandingkan kueri Anda dengan skema dan data Anda sendiri, daripada memercayai pengujian saya.
Apakah itu desain yang bagus atau tidak sangat tergantung pada aplikasi spesifik Anda. Dalam hal pemeliharaan, saya tidak melihat ada masalah khusus. Ini menyederhanakan kode aplikasi Anda dan berarti lebih sedikit yang harus dipertahankan di bagian aplikasi tersebut. Jika PG dapat memberikan hasil yang Anda butuhkan di luar kotak, satu-satunya alasan yang dapat saya pikirkan untuk tidak menggunakannya adalah pertimbangan kinerja. Jangan menemukan kembali roda dan segalanya.
Null
Fungsi agregat biasanya mengembalikan NULL
ketika mereka beroperasi lebih dari nol baris. Jika memungkinkan, Anda mungkin ingin menggunakan COALESCE
untuk menghindari mereka. Beberapa contoh:
SELECT COALESCE(json_agg(t), '[]'::json) FROM t
Atau
SELECT to_jsonb(COALESCE(array_agg(t), ARRAY[]::t[])) FROM t
Kredit untuk Hannes Landeholm karena menunjukkan hal ini