使用postgres将行减少为json键/值对

时间:2016-10-04 14:17:58

标签: javascript json postgresql

我有一个像这样的postgres表。

+----+-----------+----------------------+--------+
| id |    Key    |        Value         | userId |
+----+-----------+----------------------+--------+
|  1 | email     | thomas@reggi.com     |      1 |
|  2 | firstName | thomas               |      1 |
|  3 | lastName  | reggi                |      1 |
|  4 | email     | new.thomas@reggi.com |      1 |
+----+-----------+----------------------+--------+

我正在寻找一种方法来减少"这个表下到一个json对象。

{
   "email": "new.thomas@reggi.com",
   "firstName": "thomas",
   "lastName": "reggi"
}

只使用postgres,我能接近多少?

2 个答案:

答案 0 :(得分:2)

如果该表名为data,请尝试此操作(jsonb_pretty仅用于显示目的):

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

┌──────────────────────────────────────┐
│             jsonb_pretty             │
├──────────────────────────────────────┤
│ {                                   ↵│
│     "email": "new.thomas@reggi.com",↵│
│     "lastName": "reggi",            ↵│
│     "firstName": "thomas"           ↵│
│ }                                    │
└──────────────────────────────────────┘
(1 row)

这取决于jsonb不保留重复键的功能。

它还依赖于jsonb将始终保留最后添加的键/值对的事实。

答案 1 :(得分:1)

如果您想始终拥有密钥的最新值,可以使用CTERANK()窗口函数:

SELECT * FROM p;
┌────┬───────────┬──────────────────────┬────────┬────────────────────────────┐
│ id │    key    │        value         │ userid │     modification_time      │
├────┼───────────┼──────────────────────┼────────┼────────────────────────────┤
│  1 │ email     │ thomas@reggi.com     │      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     │ new.thomas@reggi.com │      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" : "new.thomas@reggi.com", "firstName" : "thomas", "lastName" : "reggi" } │ 2016-11-06 15:53:48.025775      │
└────────┴────────────────────────────────────────────────────────────────────────────────────┴─────────────────────────────────┘
(1 row)