Truy vấn cho các phần tử mảng bên trong kiểu JSON


118

Tôi đang cố gắng kiểm tra jsonkiểu trong PostgreSQL 9.3.
Tôi có một jsoncột được gọi datatrong một bảng được gọi là reports. JSON trông giống như sau:

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

Tôi muốn truy vấn bảng cho tất cả các báo cáo khớp với giá trị 'src' trong mảng 'đối tượng'. Ví dụ: có thể truy vấn DB cho tất cả các báo cáo phù hợp 'src' = 'foo.png'không? Tôi đã viết thành công một truy vấn có thể khớp với "background":

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

Nhưng vì "objects"có một mảng giá trị, tôi dường như không thể viết một cái gì đó hoạt động. Có thể truy vấn DB cho tất cả các báo cáo phù hợp 'src' = 'foo.png'không? Tôi đã xem qua các nguồn này nhưng vẫn không thể lấy được:

Tôi cũng đã thử những thứ như thế này nhưng vô ích:

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

Tôi không phải là chuyên gia SQL, vì vậy tôi không biết mình đang làm gì sai.

Câu trả lời:


214

json trong Postgres 9.3+

Bỏ hợp nhất mảng JSON với hàm json_array_elements()trong một phép nối bên trong FROMmệnh đề và kiểm tra các phần tử của nó:

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';

Các CTE ( WITHquery) chỉ thay thế cho một bảng reports.
Hoặc, tương đương với chỉ một mức lồng ghép duy nhất :

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

->>, ->và các #>toán tử được giải thích trong sách hướng dẫn.

Cả hai truy vấn đều sử dụng ẩn JOIN LATERAL.

SQL Fiddle.

Câu trả lời liên quan chặt chẽ:

jsonb trong Postgres 9.4+

Sử dụng tương đương jsonb_array_elements().

Tốt hơn , hãy sử dụng toán tử "chứa" mới @>(tốt nhất là kết hợp với chỉ mục GIN phù hợp trên biểu thức 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"}]';

Vì khóa objectschứa một mảng JSON , chúng tôi cần phải khớp cấu trúc trong cụm từ tìm kiếm và bao bọc phần tử mảng trong dấu ngoặc vuông. Bỏ dấu ngoặc mảng khi tìm kiếm một bản ghi thuần túy.

Giải thích chi tiết và các tùy chọn khác:


1
@pacothelovetaco: đã thêm bản cập nhật cho jsonb/ pg 9.4. Ngoài ra: đối với trường hợp đơn giản (1 mức lồng nhau), ->toán tử cũng thực hiện thủ thuật jsontrong trang 9.3.
Erwin Brandstetter

1
@pacothelovetaco, đối với trang 9.3, '#>' không phải là nước sốt bí mật, '->' sẽ phù hợp với trường hợp của bạn vì nó cũng trả về json objec. '#>' sẽ hữu ích hơn trong trường hợp đường dẫn json lồng nhau vì nó cho phép bạn dễ dàng chỉ định đường dẫn trong '{}'
Gob00st

1
@> '[{"src": "foo.png"}]'; làm việc tốt trong điều kiện nhưng làm thế nào để xóa đối tượng cụ thể như thế này? tôi không biết chỉ mục của đối tượng này. tôi muốn xóa theo giá trị khóa.
Pranay Soni,

1
@PranaySoni: Vui lòng đặt câu hỏi mới dưới dạng câu hỏi . Nhận xét không phải là nơi. Bạn luôn có thể liên kết đến cái này để biết ngữ cảnh.
Erwin Brandstetter,

@ErwinBrandstetter thân mến, có thể tìm thấy cả hai tài liệu bằng cách đối sánh từng phần không? Ví dụ: tôi muốn nhận được cả hai bản ghi như vậy '[{"src": ". Png"}]'
Pyrejkee

8

Tạo bảng với cột là kiểu json

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

Bây giờ hãy chèn dữ liệu 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}');

Bây giờ chúng ta hãy thực hiện một số truy vấn để tìm nạp dữ liệu

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

Bạn có thể nhận thấy rằng kết quả đi kèm với dấu phẩy ngược (") và dấu ngoặc ([])

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

Bây giờ để truy xuất chỉ các giá trị chỉ cần sử dụng ->>

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
Đây là tiếng ồn được định dạng dễ chịu mà không có kết nối rõ ràng với câu hỏi.
Erwin Brandstetter

4
Tôi thấy điều này hữu ích. Chương trình như thế nào để khoan vào mảng trong một jsonb
GavinBelson

0

chọn dữ liệu -> 'đối tượng' -> 0 -> 'src' làm SRC từ bảng nơi dữ liệu -> 'đối tượng' -> 0 -> 'src' = 'foo.png'


2
Điều này sẽ hữu ích CHỈ NẾU bạn biết chỉ số, là 0
Buyut Joko Rivai

có nhưng có một cách để làm bùng nổ đối tượng mảng sẽ lập bản đồ hàng khôn ngoan và chúng ta có thể sử dụng cách đó. Đúng nếu tôi đã sai lầm.
anand shukla

không phải là một giải pháp tốt vì bạn không thể chắc chắn, "src" ở vị trí 0.
simUser
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.