Làm thế nào để có được đối tượng cụ thể từ mảng jsonb trong PostgreSQL?


15

Tôi có một trường được gọi là 'người dùng' chứa một mảng json trông gần giống như thế này:

"user":

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

Bây giờ tôi muốn một truy vấn như:

select count from tablename where id = "1"

Tôi không thể lấy trường cụ thể counttừ một loạt các đối tượng json trong PostgreQuery 9.4.

Câu trả lời:


17

Sẽ hiệu quả hơn nhiều khi lưu trữ các giá trị của bạn trong một lược đồ chuẩn hóa. Điều đó nói rằng, bạn cũng có thể làm cho nó hoạt động với thiết lập hiện tại của bạn.

Giả định

Giả sử định nghĩa bảng này:

CREATE TABLE tbl (tbl_id int, usr jsonb);

"người dùng" là một từ dành riêng và sẽ yêu cầu trích dẫn kép để được sử dụng làm tên cột. Đừng làm vậy. Tôi sử dụng usrthay thế.

Truy vấn

Truy vấn không tầm thường như các bình luận (hiện đã bị xóa) có vẻ như:

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 bước cơ bản :

1. Xác định hàng đủ điều kiện với giá rẻ

WHERE t.usr @> '[{"_id":"1"}]'xác định các hàng với đối tượng phù hợp trong mảng JSON. Biểu thức có thể sử dụng chỉ mục GIN chung trên jsonbcột hoặc một chỉ mục với lớp toán tử chuyên biệt hơn jsonb_path_ops:

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

WHEREMệnh đề được thêm vào là hợp lý , nhưng nó được yêu cầu sử dụng chỉ mục. Biểu thức trong mệnh đề nối thực thi cùng một điều kiện nhưng chỉ sau khi hủy bỏ mảng trong mỗi hàng đủ điều kiện cho đến nay. Với hỗ trợ chỉ mục, Postgres chỉ xử lý các hàng có chứa một đối tượng đủ điều kiện để bắt đầu. Không quan trọng lắm với các bảng nhỏ, tạo ra sự khác biệt lớn với các bảng lớn và chỉ một vài hàng đủ điều kiện.

Liên quan:

2. Xác định (các) đối tượng phù hợp trong mảng

Vô duyên với jsonb_array_elements(). ( unnest()chỉ tốt cho các kiểu mảng Postgres.) Vì chúng tôi chỉ quan tâm đến các đối tượng thực sự khớp, hãy lọc trong điều kiện nối ngay lập tức.

Liên quan:

3. Trích xuất giá trị cho khóa lồng nhau 'count'

Sau khi các đối tượng đủ điều kiện đã được trích xuất, chỉ cần : obj.val->>'count'.


2
Nơi nào obj(value)đến từ đâu? Là nó trên LATERAL JOIN, jsonb_array_elementshoặc ở một nơi khác?
Tyler DeWitt

Có vẻ như định dạng có thể đã bị sai lệch. Tôi có đọc chính xác không JOIN LATERAL jsonb_array_elements(t.usr) obj(value) is short for JOIN LATERAL jsonb_array_elements(t.usr) AS obj(value)và đó obj(value)là bí danh bảng và cột? Trong ví dụ này, nếu objlà bí danh bảng, thì nó là bí danh gì? Bộ trả về từ jsonb_array_elementsđâu?
Tyler DeWitt

1
vâng, vâng tôi xóa bình luận tranh giành của tôi.
Erwin Brandstetter

Có cần phải sử dụng bí danh cột không? Trong thử nghiệm của tôi, JOIN LATERAL jsonb_array_elements(t.usr) obj ON obj->>'_id' = '1'có hiệu ứng tương tự (một khi bạn cập nhật câu lệnh chọn để sử dụng valuethay vì val). Dường như jsonb_array_elements(t.usr)trả về một bảng chỉ có một cột. Là postgres là thông minh và nhận ra đó obj ->>là giống như obj.val ->>?
Tyler DeWitt

Chỉ với một cột duy nhất, Postgres sử dụng một bí danh nhất định làm tên bảng tên cột. Tôi chỉ rõ ràng vì có nhiều hàm trả về thiết lập trả về nhiều hơn một cột.
Erwin Brandstetter
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.