TL; DR
SELECT json_agg(t) FROM t
untuk larik 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 membuat larik objek JSON, dengan setiap baris diubah menjadi satu objek. Hasilnya terlihat seperti ini:
[{"a":1,"b":"value1"},{"a":2,"b":"value2"},{"a":3,"b":"value3"}]
9.3 dan lebih tinggi
The json_aggFungsi menghasilkan hasil ini keluar dari kotak. Ini secara otomatis mencari cara untuk mengubah inputnya menjadi JSON dan menggabungkannya menjadi sebuah array.
SELECT json_agg(t) FROM t
Tidak ada jsonb(diperkenalkan pada 9.4) versi json_agg. Anda dapat menggabungkan baris menjadi array dan kemudian mengonversinya:
SELECT to_jsonb(array_agg(t)) FROM t
atau gabungkan json_aggdengan pemeran:
SELECT json_agg(t)::jsonb FROM t
Pengujian saya menunjukkan bahwa menggabungkan mereka ke dalam array terlebih dahulu sedikit lebih cepat. Saya menduga bahwa ini karena pemeran harus mengurai seluruh hasil JSON.
9.2
9.2 tidak memiliki json_aggatau to_jsonfungsi, jadi Anda perlu menggunakan yang lebih lama array_to_json:
SELECT array_to_json(array_agg(t)) FROM t
Anda secara opsional dapat menyertakan row_to_jsonpanggilan 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 kinerja yang signifikan antara keduanya.
Objek daftar
Bagian ini menjelaskan cara membuat objek JSON, dengan setiap kunci menjadi kolom di tabel dan setiap nilai menjadi larik nilai kolom. Hasilnya terlihat seperti ini:
{"a":[1,2,3], "b":["value1","value2","value3"]}
9.5 dan lebih tinggi
Kami dapat memanfaatkan json_build_objectfungsinya:
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)
FROM t
Anda juga bisa 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 soal opini. Jika menggunakanjson_build_object fungsi ini, saya sangat menyarankan untuk meletakkan satu pasangan kunci / nilai pada satu baris untuk meningkatkan keterbacaan.
Anda juga bisa menggunakan array_aggsebagai pengganti json_agg, tetapi pengujian saya menunjukkan bahwa json_aggsedikit lebih cepat.
Tidak ada jsonbversi dari json_build_objectfungsi tersebut. 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
Berbeda dengan query lain untuk jenis hasil ini, array_aggsepertinya menjadi sedikit lebih cepat saat digunakan 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
The to_jsonbVersi memungkinkan Anda untuk menghindari pemain dan lebih cepat, menurut pengujian saya; sekali lagi, saya menduga ini karena overhead parsing dan memvalidasi hasilnya.
9.4 dan 9.3
The json_build_objectfungsi baru untuk 9,5, sehingga Anda harus agregat dan mengkonversi 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 jsonatau jsonb.
(9.3 tidak memiliki jsonb.)
9.2
Di 9.2, bahkan tidak to_jsonada. 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 dalam fungsi JSON .
json_aggada di halaman fungsi agregat .
Rancangan
Jika kinerja itu penting, pastikan Anda mengukur kueri Anda terhadap skema dan data Anda sendiri, daripada mempercayai 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 semuanya.
Nulls
Fungsi agregat biasanya memberikan kembali NULLketika mereka beroperasi pada baris nol. Jika ini adalah kemungkinan, Anda mungkin ingin menggunakan COALESCEuntuk menghindarinya. Beberapa contoh:
SELECT COALESCE(json_agg(t), '[]'::json) FROM t
Atau
SELECT to_jsonb(COALESCE(array_agg(t), ARRAY[]::t[])) FROM t
Kredit ke Hannes Landeholm untuk menunjukkan ini