PostgreSQLは結果セットをJSON配列として返しますか?


134

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ライブラリへの依存関係がまだ含まれていないため、より単純になります。


1
PG 9.4がベータ1リリースで利用可能になり、バイナリI / Oを含むJSONのサポートが改善されました。開発マシンを使用している場合は、チェックアウトすることをお勧めします。
Patrick

@Patrick:ありがとう、json_object()は9.4の新しい関数のように見えます。もしあれば、SELECT json_object(array_agg(ta)、array_agg(tb))FROM tのようなものを試します
engineerX

回答:


265

TL; DR

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"}]

9.3以降

このjson_agg関数は、この結果をそのまま使用します。入力をJSONに変換する方法を自動的に判断し、それを配列に集約します。

SELECT json_agg(t) FROM t

jsonb(9.4で導入された)バージョンはありませんjson_agg。行を配列に集約してから変換できます。

SELECT to_jsonb(array_agg(t)) FROM t

またはjson_aggキャストと組み合わせる:

SELECT json_agg(t)::jsonb FROM t

私のテストでは、最初にそれらを配列に集約する方が少し高速であることを示しています。これはキャストがJSONの結果全体を解析する必要があるためだと思います。

9.2

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"]}

9.5以上

私たちは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つのキーと値のペアを1行に配置することを強くお勧めします。

array_agg代わりに使用することもできますjson_aggが、私のテストでは、それjson_aggがわずかに速いことが示されています。

関数のjsonbバージョンはありませんjson_build_object。単一の行に集約して変換できます。

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の結果を解析して検証するオーバーヘッドが原因であると思いますjson_agg

または、明示的なキャストを使用できます。

SELECT
    json_build_object(
        'a', json_agg(t.a),
        'b', json_agg(t.b)
    )::jsonb
FROM t

to_jsonb私のテストによると、このバージョンではキャストを回避でき、高速です。繰り返しますが、これは結果の解析と検証のオーバーヘッドによるものだと思います。

9.4および9.3

この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

あなたがしたいかに応じてjsonjsonb

(9.3にはありませんjsonb。)

9.2

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機能のドキュメント検索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

これ指摘してくれHannes Landeholmの功績


3
お返事ありがとうございます。2番目の質問SELECT row_to_json(row(array_agg(ta)、array_agg(tb)))FROM tへの回答を見つけるように私を奮い立たせましたが、結果にはaとbの代わりにラベルとして「f1」と「f2」が含まれています。
engineerX

@engineerX回答を拡大しました。
jpmc26 2014年

3
内部選択(tからの)がゼロ行を返すときに、空のJSON配列の代わりにNULLを取得することが望ましくない場合があります。これは、行を選択しない場合に常にNULLを返し、coalesceで解決可能な集約関数により発生します:array_to_json(coalesce(array_agg(t)、array [] :: record []))。
Hannes Landeholm、2015

3
あなたが使用することができる to_jsonのではなく、row_to_jsonかつarray_to_json
itsnikolay

(複数の)特定の列を選択するには、それらを単一の引数として渡す必要があります-丸括弧のようなリストSELECT json_agg((column1, column2, ...)) FROM t -余分な括弧に注意してください。これは、「箱から出しただけ」では明白でない場合があります。
jave.web

19

また、テーブルからフィールドを選択して集計したい場合は、配列として。

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'}]
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.