PostgreSQLにクエリの結果を1つのJSON配列として返すようにしたいと思います。与えられた
create table t (a int primary key, b text);
insert into t values (1, 'value1');
insert into t values (2, 'value2');
insert into t values (3, 'value3');
似たようなものが欲しい
[{"a":1,"b":"value1"},{"a":2,"b":"value2"},{"a":3,"b":"value3"}]
または
{"a":[1,2,3], "b":["value1","value2","value3"]}
(実際には、両方を知っている方が便利です)。私はいくつかのことを試しました
select row_to_json(row) from (select * from t) row;
select array_agg(row) from (select * from t) row;
select array_to_string(array_agg(row), '') from (select * from t) row;
そして、私は近くにいるように感じますが、実際にはそこにはありません。 9.15。JSON関数と演算子 以外のドキュメントを見る必要がありますか?
ちなみに、私は自分のアイデアについてはわかりません。これは通常の設計上の決定ですか?もちろん、上記の3つのクエリの最初の結果(たとえば)を取得し、クライアントに提供する前にアプリケーションで少し操作することもできますが、PostgreSQLが最終的なJSONオブジェクトを直接作成できる場合、私のアプリケーションにはJSONライブラリへの依存関係をまだ含めていないため、それはより簡単です。
SELECT json_agg(t) FROM t
オブジェクトのJSON配列の場合、および
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)
FROM t
配列のJSONオブジェクトの場合。
このセクションでは、オブジェクトのJSON配列を生成する方法について説明します。各行は単一のオブジェクトに変換されます。結果は次のようになります。
[{"a":1,"b":"value1"},{"a":2,"b":"value2"},{"a":3,"b":"value3"}]
json_agg
関数は、すぐにこの結果を生成します。入力をJSONに変換する方法を自動的に計算し、配列に集約します。
SELECT json_agg(t) FROM t
json_agg
のjsonb
(9.4で導入)バージョンはありません。行を配列に集約してから変換できます。
SELECT to_jsonb(array_agg(t)) FROM t
または、json_agg
とキャストを組み合わせます:
SELECT json_agg(t)::jsonb FROM t
私のテストでは、最初にそれらを配列に集約する方が少し速いことが示唆されています。これは、キャストがJSON結果全体を解析する必要があるためだと思われます。
9.2にはjson_agg
またはto_json
関数がないため、古いarray_to_json
を使用する必要があります。
SELECT array_to_json(array_agg(t)) FROM t
オプションで、クエリにrow_to_json
呼び出しを含めることができます。
SELECT array_to_json(array_agg(row_to_json(t))) FROM t
これにより、各行がJSONオブジェクトに変換され、JSONオブジェクトが配列として集約され、配列がJSON配列に変換されます。
2つのパフォーマンスの大きな違いを識別できませんでした。
このセクションでは、JSONオブジェクトを生成する方法について説明します。各キーはテーブルの列で、各値は列の値の配列です。結果は次のようになります。
{"a":[1,2,3], "b":["value1","value2","value3"]}
json_build_object
関数を活用できます:
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)
FROM t
列を集約して単一の行を作成し、それをオブジェクトに変換することもできます。
SELECT to_json(r)
FROM (
SELECT
json_agg(t.a) AS a,
json_agg(t.b) AS b
FROM t
) r
オブジェクトに必要な名前を付けるには、配列のエイリアスが絶対に必要であることに注意してください。
どちらが明確であるかは意見の問題です。 json_build_object
関数を使用する場合は、読みやすさを向上させるために、キー/値のペアを1行に配置することを強くお勧めします。
array_agg
の代わりにjson_agg
を使用することもできますが、私のテストでは、json_agg
がわずかに高速であることが示されています。
json_build_object
関数のjsonb
バージョンはありません。単一の行に集約して変換できます:
SELECT to_jsonb(r)
FROM (
SELECT
array_agg(t.a) AS a,
array_agg(t.b) AS b
FROM t
) r
この種の結果に対する他のクエリとは異なり、array_agg
を使用すると、to_jsonb
の方が少し高速になります。これは、json_agg
のJSON結果のオーバーヘッド解析と検証によるものと思われます。
または、明示的なキャストを使用できます。
SELECT
json_build_object(
'a', json_agg(t.a),
'b', json_agg(t.b)
)::jsonb
FROM t
私のテストによると、to_jsonb
バージョンではキャストを回避でき、より高速です。繰り返しますが、これは結果の解析と検証のオーバーヘッドによるものと思われます。
json_build_object
関数は9.5で新しく追加されたため、以前のバージョンではオブジェクトを集約して変換する必要があります。
SELECT to_json(r)
FROM (
SELECT
json_agg(t.a) AS a,
json_agg(t.b) AS b
FROM t
) r
または
SELECT to_jsonb(r)
FROM (
SELECT
array_agg(t.a) AS a,
array_agg(t.b) AS b
FROM t
) r
json
またはjsonb
のどちらが必要かによって異なります。
(9.3にはjsonb
がありません。)
9.2では、to_json
も存在しません。 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
JSON functions でJSON関数のドキュメントを検索します。
json_agg
は 集計関数 ページにあります。
パフォーマンスが重要な場合は、テストを信頼するのではなく、クエリを独自のスキーマとデータに対してベンチマークするようにしてください。
良いデザインであるかどうかは、実際に特定のアプリケーションに依存します。保守性に関しては、特に問題はありません。これにより、アプリのコードが簡素化され、アプリのその部分でのメンテナンスが少なくなります。 PGがすぐに必要な結果を正確に提供できる場合、それを使用しないと考えることができる唯一の理由は、パフォーマンスの考慮事項になります。車輪とすべてを再発明しないでください。
集約関数は、通常、ゼロ行で動作するときにNULL
を返します。これが可能であれば、COALESCE
を使用してそれらを回避することができます。いくつかの例:
SELECT COALESCE(json_agg(t), '[]'::json) FROM t
または
SELECT to_jsonb(COALESCE(array_agg(t), ARRAY[]::t[])) FROM t
また、テーブルからフィールドを選択して、配列として集約する場合もあります。
SELECT json_agg(json_build_object('data_a',a,
'data_b',b,
)) from t;
結果は来るでしょう。
[{'data_a':1,'data_b':'value1'}
{'data_a':2,'data_b':'value2'}]