TL; DR
SELECT json_agg(t) FROM t
cho một mảng JSON của các đối tượng 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 các đối tượng JSON, với mỗi hàng được chuyển đổi thành một đối tượng. Kết quả trông như thế này:
[{"a":1,"b":"value1"},{"a":2,"b":"value2"},{"a":3,"b":"value3"}]
9.3 trở lên
Các json_agg
chức năng tạo ra kết quả này ra khỏi hộp. 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
(giới thiệu trong phiên bản 9.4) 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 tổng hợp chúng thành một mảng đầu tiên nhanh hơn một chút. Tôi nghi ngờ rằng điều này là do các diễn viên phải phân tích toàn bộ kết quả JSON.
9,2
9.2 không có json_agg
hoặc các to_json
chức năng, vì vậy bạn cần sử dụng cũ hơn array_to_json
:
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
cuộc gọi trong truy vấn:
SELECT array_to_json(array_agg(row_to_json(t))) FROM t
Điều này chuyển đổi mỗi 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ể nhận ra bất kỳ sự khác biệt đáng kể nào về hiệu suất giữa hai người.
Đố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. Đó là kết quả trông như thế này:
{"a":[1,2,3], "b":["value1","value2","value3"]}
9,5 trở lên
Chúng ta 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 đơn, sau đó chuyển đổi nó 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 bí danh các mảng là hoàn toàn cần thiết để đảm bảo rằng đối tượng có tên mong muốn.
Cái nào rõ ràng hơn là vấn đề quan điểm. Nếu sử dụng json_build_object
hàm, tôi 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 thế json_agg
, nhưng thử nghiệm của tôi cho thấy rằng json_agg
nó nhanh hơn một chút.
Không có jsonb
phiên bản của json_build_object
chức năng. Bạn có thể tổng hợp thành một hàng duy nhất 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
dường như 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 trên cao và xác thực kết quả JSON của json_agg
.
Hoặc bạn có thể sử dụng một diễn viên rõ ràng:
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)::jsonb
FROM t
Các to_jsonb
phiên bản cho phép bạn để tránh các diễn viên và vận hành nhanh, 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 nhận kết quả.
9,4 và 9,3
Các json_build_object
chức năng còn mới đến 9.5, vì vậy bạn phải tổng hợp và chuyển đổi sang 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 là
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
hay jsonb
.
(9.3 không có jsonb
.)
9,2
Trong 9.2, thậm chí không 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
là 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á các truy vấn của bạn 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.
Cho dù đó 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 hơn để duy trì 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 ra khỏi hộp, lý do duy nhất tôi có thể nghĩ đến để không sử dụng nó sẽ là những cân nhắc về hiệu suất. Đừng phát minh lại bánh xe và tất cả.
Không có gì
Các hàm tổng hợp thường trả lại NULL
khi chúng hoạt động trên các hàng không. Nếu đây là một 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 là
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