2016-10-04 8 views
0

私はこのようなポストグレステーブルを持っています。jsonキーと値のペアをポストグルで減らします

+----+-----------+----------------------+--------+ 
| id | Key |  Value   | userId | 
+----+-----------+----------------------+--------+ 
| 1 | email  | [email protected]  |  1 | 
| 2 | firstName | thomas    |  1 | 
| 3 | lastName | reggi    |  1 | 
| 4 | email  | [email protected] |  1 | 
+----+-----------+----------------------+--------+ 

私は、このテーブルをjsonオブジェクトに「減らす」方法を探しています。

{ 
    "email": "[email protected]", 
    "firstName": "thomas", 
    "lastName": "reggi" 
} 

ポストグルを使用するだけで、どれくらい近づけることができますか?

答えて

2

テーブルがdata呼び出された場合には、(jsonb_prettyは単に表示目的のためである)、これを試してみてください。

SELECT jsonb_pretty(
      jsonb_object_agg(key, value ORDER BY id) 
     ) 
FROM data 
WHERE userid = 1; 

┌──────────────────────────────────────┐ 
│    jsonb_pretty    │ 
├──────────────────────────────────────┤ 
│ {         ↵│ 
│  "email": "[email protected]",↵│ 
│  "lastName": "reggi",   ↵│ 
│  "firstName": "thomas"   ↵│ 
│ }         │ 
└──────────────────────────────────────┘ 
(1 row) 

これはjsonbは重複したキーを保持していないという特徴に依存しています。

また、jsonbは、の最後ののキー/値のペアが常に保持されているという事実にも依存しています。

+1

がそれを制御することができ、保管にキーを: 'jsonb_object_agg'(他の集約関数と同様)は、' ORDER BY'節、f.exを受け取ります。 'key'を最高の' id'で保持するために 'jsonb_object_agg(key、value ORDER BY id)'を使用します(最後に追加されたキーと値のペアは維持されます) – pozs

+0

はい、しかし、それは文書化されていない実装の詳細'jsonb'では、最後に追加されたペアが保持されることになります。たぶん私はあまりにも心配です。問題に対処するための答えにいくつかのアイデアを追加します。 –

+1

これは文書化されています(https://www.postgresql.org/docs/current/static/datatype-json.html):*入力に重複キーが指定されている場合、最後の値だけが保持されます。* - 'json'型でも同様の扱いがあります:*値のJSONオブジェクトに同じキーが複数回含まれている場合、すべてのキーと値のペアが保持されます。 (処理機能は最後の値を有効なものと見なします。)* – pozs

1

あなたは常にキーの最新の値を持つようにしたい場合は、あなたがCTERANK()ウィンドウ関数を使用できます。

SELECT * FROM p; 
┌────┬───────────┬──────────────────────┬────────┬────────────────────────────┐ 
│ id │ key │  value   │ userid │  modification_time  │ 
├────┼───────────┼──────────────────────┼────────┼────────────────────────────┤ 
│ 1 │ email  │ [email protected]  │  1 │ 2016-10-05 12:53:32.936704 │ 
│ 2 │ firstName │ thomas    │  1 │ 2016-10-05 12:53:32.936704 │ 
│ 3 │ lastName │ reggi    │  1 │ 2016-10-05 12:53:32.936704 │ 
│ 4 │ email  │ [email protected] │  1 │ 2016-11-06 15:53:48.025775 │ 
└────┴───────────┴──────────────────────┴────────┴────────────────────────────┘ 
(4 rows) 

WITH info_with_rank_for_user AS (
    SELECT userId, 
     modification_time, 
     value, 
     key, 
     RANK() OVER (PARTITION BY userId, key ORDER BY id DESC) 
    FROM p 
) 
SELECT userId, 
     json_object_agg(key, value), 
     MAX(modification_time) AS last_settings_modification_time 
FROM info_with_rank_for_user 
WHERE rank = 1 
GROUP BY userId 
; 
┌────────┬────────────────────────────────────────────────────────────────────────────────────┬─────────────────────────────────┐ 
│ userid │         json_object_agg         │ last_settings_modification_time │ 
├────────┼────────────────────────────────────────────────────────────────────────────────────┼─────────────────────────────────┤ 
│  1 │ { "email" : "[email protected]", "firstName" : "thomas", "lastName" : "reggi" } │ 2016-11-06 15:53:48.025775  │ 
└────────┴────────────────────────────────────────────────────────────────────────────────────┴─────────────────────────────────┘ 
(1 row) 
+0

これは完璧です!私はテーブルの上に別のコラムを持っています。だから、列は 'userId、otherColumn、json_object_agg'を出しますか? – ThomasReggi

+0

@ThomasReggi:それは 'otherColumn'が何を表すかに依存します。私は集計したいものもここに追加しました(ここでは 'MAX()'を使用しています)。それはあなたの質問にそれを追加するケースではない場合、それは他に助けるのは少し難しい:) – Marth

関連する問題