TL; DR
SELECT json_agg(t) FROM t
cho một mảng đối tượng JSON và
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)
FROM t
cho một đối tượng JSON của mảng.
Danh sách các đối tượng
Phần này mô tả cách tạo một mảng đối tượng JSON, với mỗi hàng được chuyển đổi thành một đối tượng duy nhất. Kết quả như sau:
[{"a":1,"b":"value1"},{"a":2,"b":"value2"},{"a":3,"b":"value3"}]
9.3 trở lên
json_agg
hàm tạo ra kết quả này. Nó tự động tìm ra cách chuyển đổi đầu vào của nó thành JSON và tổng hợp nó thành một mảng.
SELECT json_agg(t) FROM t
Không có jsonb
(được giới thiệu trong 9.4) phiên bản của json_agg
. Bạn có thể tổng hợp các hàng thành một mảng và sau đó chuyển đổi chúng:
SELECT to_jsonb(array_agg(t)) FROM t
hoặc kết hợp json_agg
với dàn diễn viên:
SELECT json_agg(t)::jsonb FROM t
Thử nghiệm của tôi cho thấy rằng việc tổng hợp chúng thành một mảng trước tiên sẽ nhanh hơn một chút. Tôi nghi ngờ rằng điều này là do diễn viên phải phân tích cú pháp toàn bộ kết quả JSON.
9.2
9.2 không có json_agg
hoặc to_json
, vì vậy bạn cần sử dụng array_to_json
cũ hơn :
SELECT array_to_json(array_agg(t)) FROM t
Bạn có thể tùy chọn bao gồm một row_to_json
gọi trong truy vấn:
SELECT array_to_json(array_agg(row_to_json(t))) FROM t
Điều này sẽ chuyển đổi từng hàng thành một đối tượng JSON, tổng hợp các đối tượng JSON thành một mảng và sau đó chuyển đổi mảng thành một mảng JSON.
Tôi không thể phân biệt được bất kỳ sự khác biệt đáng kể nào về hiệu suất giữa cả hai.
Đối tượng của danh sách
Phần này mô tả cách tạo một đối tượng JSON, với mỗi khóa là một cột trong bảng và mỗi giá trị là một mảng các giá trị của cột. Kết quả giống như sau:
{"a":[1,2,3], "b":["value1","value2","value3"]}
9.5 trở lên
Chúng tôi có thể tận dụng json_build_object
chức năng:
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)
FROM t
Bạn cũng có thể tổng hợp các cột, tạo một hàng, sau đó chuyển đổi hàng đó thành một đối tượng:
SELECT to_json(r)
FROM (
SELECT
json_agg(t.a) AS a,
json_agg(t.b) AS b
FROM t
) r
Lưu ý rằng việc đặt răng cưa cho các mảng là hoàn toàn cần thiết để đảm bảo rằng đối tượng có các tên mong muốn.
Cái nào rõ ràng hơn là một vấn đề của ý kiến. Nếu sử dụng json_build_object
, tôi thực sự khuyên bạn nên đặt một cặp khóa / giá trị trên một dòng để cải thiện khả năng đọc.
Bạn cũng có thể sử dụng array_agg
thay cho json_agg
, nhưng thử nghiệm của tôi chỉ ra rằng json_agg
nhanh hơn một chút.
Không có jsonb
phiên bản của json_build_object
hàm số. Bạn có thể tổng hợp thành một hàng và chuyển đổi:
SELECT to_jsonb(r)
FROM (
SELECT
array_agg(t.a) AS a,
array_agg(t.b) AS b
FROM t
) r
Không giống như các truy vấn khác cho loại kết quả này, array_agg
có vẻ nhanh hơn một chút khi sử dụng to_jsonb
. Tôi nghi ngờ điều này là do phân tích cú pháp chi phí và xác thực kết quả JSON của json_agg
.
Hoặc bạn có thể sử dụng một dàn diễn viên rõ ràng:
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)::jsonb
FROM t
to_jsonb
phiên bản cho phép bạn tránh diễn viên và nhanh hơn, theo thử nghiệm của tôi; một lần nữa, tôi nghi ngờ điều này là do chi phí phân tích cú pháp và xác thực kết quả.
9,4 và 9,3
json_build_object
hàm mới lên 9.5, vì vậy bạn phải tổng hợp và chuyển đổi thành một đối tượng trong các phiên bản trước:
SELECT to_json(r)
FROM (
SELECT
json_agg(t.a) AS a,
json_agg(t.b) AS b
FROM t
) r
hoặc
SELECT to_jsonb(r)
FROM (
SELECT
array_agg(t.a) AS a,
array_agg(t.b) AS b
FROM t
) r
tùy thuộc vào việc bạn muốn json
hoặc jsonb
.
(9.3 không có jsonb
.)
9.2
Trong 9.2, thậm chí không phải to_json
tồn tại. Bạn phải sử dụng row_to_json
:
SELECT row_to_json(r)
FROM (
SELECT
array_agg(t.a) AS a,
array_agg(t.b) AS b
FROM t
) r
Tài liệu
Tìm tài liệu cho các hàm JSON trong các hàm JSON.
json_agg
nằm trên trang chức năng tổng hợp.
Thiết kế
Nếu hiệu suất là quan trọng, hãy đảm bảo bạn đánh giá chuẩn các truy vấn của mình dựa trên lược đồ và dữ liệu của riêng bạn, thay vì tin tưởng vào thử nghiệm của tôi.
Đó là một thiết kế tốt hay không thực sự phụ thuộc vào ứng dụng cụ thể của bạn. Về khả năng bảo trì, tôi không thấy bất kỳ vấn đề cụ thể nào. Nó đơn giản hóa mã ứng dụng của bạn và có nghĩa là có ít thứ phải duy trì hơn trong phần đó của ứng dụng. Nếu PG có thể cung cấp cho bạn chính xác kết quả bạn cần, lý do duy nhất tôi có thể nghĩ đến để không sử dụng nó là cân nhắc về hiệu suất. Đừng phát minh lại bánh xe và tất cả.
Nulls
Các hàm tổng hợp thường trả về NULL
khi chúng hoạt động trên không hàng. Nếu đây là khả năng, bạn có thể muốn sử dụng COALESCE
để tránh chúng. Một vài ví dụ:
SELECT COALESCE(json_agg(t), '[]'::json) FROM t
Hoặc
SELECT to_jsonb(COALESCE(array_agg(t), ARRAY[]::t[])) FROM t
Tín dụng cho Hannes Landeholm vì đã chỉ ra điều này