ค้นหาองค์ประกอบอาร์เรย์ภายในประเภท JSON


118

ฉันกำลังพยายามทดสอบjsonประเภทใน PostgreSQL 9.3
ฉันมีjsonคอลัมน์ที่เรียกว่าในตารางที่เรียกว่าdata reportsJSON มีลักษณะดังนี้:

{
  "objects": [
    {"src":"foo.png"},
    {"src":"bar.png"}
  ],
  "background":"background.png"
}

ฉันต้องการสอบถามตารางสำหรับรายงานทั้งหมดที่ตรงกับค่า "src" ในอาร์เรย์ "วัตถุ" ยกตัวอย่างเช่นมันเป็นไปได้ที่จะสอบถาม DB สำหรับรายงานทั้งหมดที่จับคู่'src' = 'foo.png'? ฉันเขียนข้อความค้นหาที่ตรงกับ"background":

SELECT data AS data FROM reports where data->>'background' = 'background.png'

แต่เนื่องจาก"objects"มีอาร์เรย์ของค่าดูเหมือนว่าฉันจะเขียนสิ่งที่ใช้งานไม่ได้ มันเป็นไปได้ที่จะสอบถาม DB สำหรับรายงานทั้งหมดที่จับคู่'src' = 'foo.png'? ฉันได้ตรวจสอบแหล่งที่มาเหล่านี้แล้ว แต่ยังไม่สามารถรับได้:

ฉันได้ลองทำสิ่งนี้เช่นกัน แต่ไม่มีประโยชน์:

SELECT json_array_elements(data->'objects') AS data from reports
WHERE  data->>'src' = 'foo.png';

ฉันไม่ใช่ผู้เชี่ยวชาญด้าน SQL ดังนั้นฉันจึงไม่รู้ว่าฉันทำอะไรผิด

คำตอบ:


215

json ใน Postgres 9.3+

ยกเลิกการทดสอบอาร์เรย์ JSON ด้วยฟังก์ชันjson_array_elements()ในการรวมด้านข้างในส่วนFROMคำสั่งและทดสอบองค์ประกอบ:

WITH reports(data) AS (
   VALUES ('{"objects":[{"src":"foo.png"}, {"src":"bar.png"}]
           , "background":"background.png"}'::json)
   ) 
SELECT *
FROM   reports r, json_array_elements(r.data#>'{objects}') obj
WHERE  obj->>'src' = 'foo.png';

CTE ( WITHแบบสอบถาม) reportsเพียงทดแทนสำหรับตาราง
หรือเทียบเท่าเพียงระดับเดียวของการซ้อน:

SELECT *
FROM   reports r, json_array_elements(r.data->'objects') obj
WHERE  obj->>'src' = 'foo.png';

->>, ->และ#>ผู้ประกอบการมีการอธิบายในคู่มือการใช้งาน

JOIN LATERALคำสั่งทั้งสองใช้โดยปริยาย

SQL Fiddle

คำตอบที่เกี่ยวข้องอย่างใกล้ชิด:

jsonb ใน Postgres 9.4+

jsonb_array_elements()ใช้เทียบเท่า

ยังดีกว่าให้ใช้ตัวดำเนินการ "มี" ใหม่@>(ดีที่สุดเมื่อใช้ร่วมกับดัชนี GIN ที่ตรงกันในนิพจน์data->'objects'):

CREATE INDEX reports_data_gin_idx ON reports
USING gin ((data->'objects') jsonb_path_ops);

SELECT * FROM reports WHERE data->'objects' @> '[{"src":"foo.png"}]';

เนื่องจากคีย์objectsมีอาร์เรย์ JSON เราจึงต้องจับคู่โครงสร้างในข้อความค้นหาและรวมองค์ประกอบอาร์เรย์ไว้ในวงเล็บเหลี่ยมด้วย วางวงเล็บอาร์เรย์เมื่อค้นหาระเบียนธรรมดา

คำอธิบายโดยละเอียดและตัวเลือกเพิ่มเติม:


1
@pacothelovetaco: เพิ่มการอัปเดตสำหรับjsonb/ pg 9.4 นอกจากนี้: สำหรับกรณีง่ายๆ (1 ระดับของการซ้อน) ตัว->ดำเนินการยังทำเคล็ดลับสำหรับjsonในหน้า 9.3
Erwin Brandstetter

1
@pacothelovetaco สำหรับ pg 9.3, '#>' ไม่ใช่ซอสลับ '->' จะดีสำหรับกรณีของคุณเพราะจะส่งคืน json objec ด้วย "#>" จะมีประโยชน์มากกว่าในกรณีพา ธ json ที่ซ้อนกันเนื่องจากช่วยให้คุณระบุพา ธ ได้อย่างง่ายดายใน "{}"
Gob00st

1
@> '[{"src": "foo.png"}]'; ทำงานได้ดีในสภาพที่ แต่จะลบวัตถุเฉพาะเช่นนี้ได้อย่างไร? ฉันไม่รู้ดัชนีของวัตถุนี้ ฉันต้องการลบตามค่าคีย์
Pranay Soni

1
@PranaySoni: กรุณาถามคำถามใหม่เป็นคำถาม ความคิดเห็นไม่ใช่สถานที่ คุณสามารถเชื่อมโยงไปยังบริบทนี้ได้ตลอดเวลา
Erwin Brandstetter

ที่รัก @ErwinBrandstetter เป็นไปได้ไหมที่จะค้นหาเอกสารทั้งสองโดยการจับคู่บางส่วน ตัวอย่างเช่นฉันต้องการรับบันทึกทั้งสองรายการแบบนั้น '[{"src": ". png"}]'
Pyrejkee

8

สร้างตารางที่มีคอลัมน์เป็นประเภท json

CREATE TABLE friends ( id serial primary key, data jsonb);

ตอนนี้ขอแทรกข้อมูล json

INSERT INTO friends(data) VALUES ('{"name": "Arya", "work": ["Improvements", "Office"], "available": true}');
INSERT INTO friends(data) VALUES ('{"name": "Tim Cook", "work": ["Cook", "ceo", "Play"], "uses": ["baseball", "laptop"], "available": false}');

ตอนนี้เรามาสร้างแบบสอบถามเพื่อดึงข้อมูล

select data->'name' from friends;
select data->'name' as name, data->'work' as work from friends;

คุณอาจสังเกตเห็นว่าผลลัพธ์มาพร้อมกับเครื่องหมายจุลภาคกลับด้าน (") และเครื่องหมายวงเล็บ ([])

    name    |            work            
------------+----------------------------
 "Arya"     | ["Improvements", "Office"]
 "Tim Cook" | ["Cook", "ceo", "Play"]
(2 rows)

ตอนนี้เพื่อดึงเฉพาะค่าที่ใช้ ->>

select data->>'name' as name, data->'work'->>0 as work from friends;
select data->>'name' as name, data->'work'->>0 as work from friends where data->>'name'='Arya';

22
นี่คือเสียงรบกวนในรูปแบบที่น่าพึงพอใจโดยไม่มีการเชื่อมต่อกับคำถามที่มองเห็นได้
Erwin Brandstetter

4
ฉันพบว่าสิ่งนี้มีประโยชน์ แสดงวิธีเจาะเข้าไปในอาร์เรย์ใน jsonb
GavinBelson

0

เลือกข้อมูล -> 'วัตถุ' -> 0 -> 'src' เป็น SRC จากตารางที่ข้อมูล -> 'วัตถุ' -> 0 -> 'src' = 'foo.png'


2
สิ่งนี้จะมีประโยชน์ก็ต่อเมื่อคุณรู้จักดัชนีซึ่งเป็น 0 เท่านั้น
Buyut Joko Rivai

ใช่ แต่มีวิธีการระเบิดวัตถุอาร์เรย์ซึ่งจะแมปแถวอย่างชาญฉลาดและเราสามารถใช้สิ่งนั้นได้ แก้ไขฉันถ้าฉันผิด
anand shukla

ไม่ใช่วิธีแก้ปัญหาที่ดีอย่างที่คุณแน่ใจไม่ได้ "src" อยู่ในตำแหน่ง 0
simUser
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.