วิธีรับวัตถุเฉพาะจากอาร์เรย์ jsonb ใน PostgreSQL


16

ฉันมีเขตข้อมูลที่เรียกว่า 'ผู้ใช้' ที่มีอาร์เรย์ json ที่มีลักษณะเช่นนี้:

"user":

[{ "_id" : "1", "count" : "4" }, { "_id" : "3", "count": "4"}]

ตอนนี้ฉันต้องการแบบสอบถามเช่น:

select count from tablename where id = "1"

ฉันไม่สามารถรับฟิลด์เฉพาะcountจากอาร์เรย์ของวัตถุ json ใน PostgreSQL 9.4

คำตอบ:


17

มันจะมีประสิทธิภาพมากขึ้นในการจัดเก็บค่าของคุณในสคีมาปกติ ที่กล่าวว่าคุณยังสามารถใช้งานได้กับการตั้งค่าปัจจุบันของคุณ

สมมติฐาน

สมมติว่านิยามตารางนี้:

CREATE TABLE tbl (tbl_id int, usr jsonb);

"ผู้ใช้" เป็นคำที่สงวนไว้และจะต้องใช้การอ้างอิงสองครั้งเพื่อใช้เป็นชื่อคอลัมน์ อย่าทำอย่างนั้น ฉันใช้usrแทน

สอบถาม

ข้อความค้นหานั้นไม่สำคัญเท่ากับความคิดเห็น (ลบแล้ว) ทำให้ดูเหมือนว่า:

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"}]';

มี3 ขั้นตอนพื้นฐาน :

1. ระบุแถวที่มีคุณสมบัติเหมาะสมในราคาถูก

WHERE t.usr @> '[{"_id":"1"}]'ระบุแถวที่มีวัตถุที่ตรงกันในอาร์เรย์ JSON นิพจน์สามารถใช้ดัชนี GIN ทั่วไปในjsonbคอลัมน์หรือหนึ่งรายการที่มีคลาสโอเปอเรเตอร์ที่เฉพาะเจาะจงมากขึ้นjsonb_path_ops:

CREATE INDEX tbl_usr_gin_idx ON tbl USING gin (usr jsonb_path_ops);

WHEREอนุประโยคที่เพิ่มเข้ามานั้นซ้ำซ้อนในเชิงตรรกะแต่จำเป็นต้องใช้ดัชนี การแสดงออกในการเข้าร่วมข้อบังคับเงื่อนไขเดียวกัน แต่หลังจากการยกเลิกอาร์เรย์ในทุกแถวที่มีคุณสมบัติจนถึงตอนนี้ ด้วยการสนับสนุนดัชนี Postgres จะประมวลผลแถวที่มีวัตถุที่มีคุณสมบัติตามที่กำหนดเพื่อเริ่มต้นเท่านั้น ไม่สำคัญกับโต๊ะเล็ก ๆ แต่สร้างความแตกต่างอย่างมากกับโต๊ะใหญ่และแถวที่มีคุณสมบัติเพียงไม่กี่แถว

ที่เกี่ยวข้อง:

2. ระบุวัตถุที่ตรงกันในอาเรย์

Unnest jsonb_array_elements()กับ ( unnest()เหมาะสำหรับประเภทอาร์เรย์ Postgres เท่านั้น) เนื่องจากเราสนใจเฉพาะวัตถุที่ตรงกันเท่านั้นจึงกรองในเงื่อนไขการเข้าร่วมได้ทันที

ที่เกี่ยวข้อง:

3. แยกค่าสำหรับคีย์ที่ซ้อนกัน 'count'

หลังจากแยกวัตถุที่ผ่านการคัดเลือกแล้วเพียง: obj.val->>'count'.


2
ที่ไหนที่ไม่obj(value)มาจากไหน? มันอยู่ในLATERAL JOINที่jsonb_array_elementsหรือที่อื่น?
Tyler DeWitt

ดูเหมือนว่าการจัดรูปแบบอาจจะทำให้เมามากขึ้น ฉันอ่านอย่างถูกต้องแล้วJOIN LATERAL jsonb_array_elements(t.usr) obj(value) is short for JOIN LATERAL jsonb_array_elements(t.usr) AS obj(value)และนั่นobj(value)คือชื่อแทนตารางและคอลัมน์? ในตัวอย่างนี้ถ้าobjเป็นนามแฝงของตารางมันคืออะไรนามแฝงไป? ชุดกลับมาจากjsonb_array_elementsไหน?
Tyler DeWitt

1
ใช่และใช่ ฉันลบความคิดเห็นที่มีสัญญาณรบกวนของฉัน
Erwin Brandstetter

จำเป็นต้องใช้นามแฝงคอลัมน์หรือไม่ ในการทดสอบของฉันJOIN LATERAL jsonb_array_elements(t.usr) obj ON obj->>'_id' = '1'มีผลเหมือนกัน (เมื่อคุณอัปเดตคำสั่ง select เพื่อใช้valueแทนval) ปรากฏว่าjsonb_array_elements(t.usr)ส่งคืนตารางที่มีเพียงหนึ่งคอลัมน์ postgres ฉลาดและรู้ตัวว่าobj ->>เป็นเช่นนั้นobj.val ->>หรือไม่?
Tyler DeWitt

มีเพียงคอลัมน์เดียว Postgres ใช้นามแฝงที่กำหนดเป็นชื่อตารางและคอลัมน์ ฉันแค่ชัดเจนเพราะมีหลายฟังก์ชั่นการคืนค่าที่ส่งกลับมากกว่าหนึ่งคอลัมน์
Erwin Brandstetter
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.