Akan jauh lebih efisien untuk menyimpan nilai Anda dalam skema yang dinormalisasi. Yang mengatakan, Anda juga dapat membuatnya bekerja dengan pengaturan Anda saat ini.
Asumsi
Dengan asumsi definisi tabel ini:
CREATE TABLE tbl (tbl_id int, usr jsonb);
"pengguna" adalah kata yang dilindungi undang - undang dan akan membutuhkan penawaran ganda untuk digunakan sebagai nama kolom. Jangan lakukan itu. Saya menggunakan usr
sebagai gantinya.
Pertanyaan
Permintaannya tidak sepele seperti komentar (sekarang dihapus) membuatnya tampak:
SELECT t.tbl_id, obj.val->>'count' AS count
FROM tbl t
JOIN LATERAL jsonb_array_elements(t.usr) obj(val) ON obj.val->>'_id' = '1'
WHERE t.usr @> '[{"_id":"1"}]';
Ada 3 langkah dasar :
1. Identifikasi baris yang memenuhi syarat dengan harga murah
WHERE t.usr @> '[{"_id":"1"}]'
mengidentifikasi baris dengan objek yang cocok dalam array JSON. Ekspresi dapat menggunakan indeks GIN umum pada jsonb
kolom, atau indeks dengan kelas operator yang lebih khusus jsonb_path_ops
:
CREATE INDEX tbl_usr_gin_idx ON tbl USING gin (usr jsonb_path_ops);
WHERE
Klausa yang ditambahkan secara logis berlebihan , tetapi diperlukan untuk menggunakan indeks. Ekspresi dalam klausa gabungan memberlakukan kondisi yang sama tetapi hanya setelah membatalkanestest array di setiap baris yang memenuhi syarat sejauh ini. Dengan dukungan indeks, Postgres hanya memproses baris yang berisi objek yang memenuhi syarat untuk memulai. Tidak terlalu menjadi masalah dengan meja kecil, membuat besar perbedaan dengan meja besar dan hanya beberapa baris kualifikasi.
Terkait:
2. Identifikasi objek yang cocok dalam array
Unnest dengan jsonb_array_elements()
. ( unnest()
hanya baik untuk jenis-jenis array Postgres.) Karena kita hanya tertarik untuk benar-benar mencocokkan objek, segera saring dalam kondisi bergabung.
Terkait:
3. Ekstrak nilai untuk kunci bersarang 'count'
Setelah benda kualifikasi telah diekstraksi, hanya: obj.val->>'count'
.
obj(value)
? Apakah itu diLATERAL JOIN
,jsonb_array_elements
atau di tempat lain?