暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PostgreSQL 从 SQL 生产 JSON 数据

在 PostgreSQL 中生成 JSON 的速度可能是将关系数据复制到应用程序,随后通过应用程序生成 JSON 的几倍。这对于返回 JSON 的 API 尤其有用。我们的示例是一个简单的书签应用。首先,我们创建一个 users 表。

 CREATE TABLE users (  id INTEGER PRIMARY KEY,  email VARCHAR NOT NULL,  name VARCHAR NOT NULL,  password_digest VARCHAR NOT NULL);

接着,我们新增一些用户。

 INSERT INTO users VALUES  (1, 'john@example.com''John''0123456789abcdef'),  (2, 'jane@example.com''Jane''abcdef0123456789');

通过下面的 SQL 查看 users表中的信息(注意,TABLE <table_name> 是 PostgreSQL 对 SQL 的扩展)。

 TABLE users;
  id |      email       | name | password_digest----+------------------+------+------------------  1 | john@example.com | John | 0123456789abcdef  2 | jane@example.com | Jane | abcdef0123456789(2 rows)

我们可以通过row_to_json 函数将一个用户对象转换为 JSON 格式的数据。

 SELECT row_to_json(users)FROM usersWHERE id = 1;

                              

         row_to_json---------------------------------------------------------------------------------------- {"id":1,"email":"john@example.com","name":"John","password_digest":"0123456789abcdef"}(1 row)

上面的示例可以工作,但是它将 users表的所有信息都返回了。实际上,我们并不想要暴露用户的密码信息。我们可以使用 row 构造器来规避这个问题。

    SELECT row_to_json(row(id, name, email))FROM usersWHERE id = 1;

                

   row_to_json---------------------------------------------- {"f1":1,"f2":"John","f3":"john@example.com"}(1 row)

这几乎也能达到我们的预期,但是 row 构造器会丢弃字段的名称。我们可以通过子查询的方式来保留字段名称。

  SELECT row_to_json(t)FROM (  SELECT id, name, email  FROM users  WHERE id = 1) t;

                   

   row_to_json--------------------------------------------------- {"id":1,"name":"John","email":"john@example.com"}(1 row)

值得一提的是,另一种解决方案是创建一个复合类型,并将行强制转换为该类型。然而,子查询方法对我来说效果更好。现在,让我们看看如何创建具有嵌套值的JSON文档。我们将从创建 bookmarks 表开始。

  CREATE TABLE bookmarks (  id SERIAL PRIMARY KEY,  user_id INTEGER NOT NULL REFERENCES users,  name VARCHAR NOT NULL,  url VARCHAR NOT NULL);

接着,插入一些示例书签。

  INSERT INTO BOOKMARKS (user_id, name, url) VALUES  (1, 'Hashrocket''https://www.hashrocket.com'),  (1, 'PostgreSQL Docs''http://www.postgresql.org/docs/current/static/index.html'),  (2, 'Google''https://www.google.com'),  (2, 'Stack Overflow''http://stackoverflow.com/'),  (2, 'YouTube''https://www.youtube.com');

让我们尝试一个嵌套的 JSON 查询。

  SELECT row_to_json(t)FROM (  SELECT    id, name, email,    (      SELECT json_agg(row_to_json(bookmarks))      FROM bookmarks      WHERE user_id = users.id    ) AS bookmarks  FROM users  WHERE id=1) t;

                                                                                                                        

row_to_json------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- {"id":1,"name":"John","email":"john@example.com","bookmarks":[{"id":1,"user_id":1,"name":"Hashrocket","url":"https://www.hashrocket.com"}, {"id":2,"user_id":1,"name":"PostgreSQL Docs","url":"http://www.postgresql.org/docs/current/static/index.html"}]}(1 row)

row_to_json 函数的第二个参数可用于格式化 JSON 数据的输出,使其更容易查看。

SELECT row_to_json(t, true)FROM (  SELECT    id, name, email,    (      SELECT json_agg(row_to_json(bookmarks, true))      FROM bookmarks      WHERE user_id = users.id    ) AS bookmarks  FROM users  WHERE id=1) t;

                       

 row_to_json---------------------------------------------------------------------- {"id":1,                                                            +  "name":"John",                                                     +  "email":"john@example.com",                                        +  "bookmarks":[{"id":1,                                              +  "user_id":1,                                                       +  "name":"Hashrocket",                                               +  "url":"https://www.hashrocket.com"}, {"id":2,                      +  "user_id":1,                                                       +  "name":"PostgreSQL Docs",                                          +  "url":"http://www.postgresql.org/docs/current/static/index.html"}]}(1 row)

唯一的变化是我们使用带有 json_agg 函数的子查询为用户聚合所有书签。json_agg 将 JSON 对象聚合到 JSON 数组中。如果我们想获取所有用户及其所有书签,我们只需删除 WHERE 子句,并将 json_agg 添加到最外层的查询中。

 SELECT json_agg(row_to_json(t, true))FROM (  SELECT    id, name, email,    (      SELECT json_agg(row_to_json(bookmarks, true))      FROM bookmarks      WHERE user_id = users.id    ) AS bookmarks  FROM users) t;

                                   

 json_agg-------------------------------------------------------------------------------- [{"id":1,                                                                     +  "name":"John",                                                               +  "email":"john@example.com",                                                  +  "bookmarks":[{"id":1,                                                        +  "user_id":1,                                                                 +  "name":"Hashrocket",                                                         +  "url":"https://www.hashrocket.com"}, {"id":2,                                +  "user_id":1,                                                                 +  "name":"PostgreSQL Docs",                                                    +  "url":"http://www.postgresql.org/docs/current/static/index.html"}]}, {"id":2,+  "name":"Jane",                                                               +  "email":"jane@example.com",                                                  +  "bookmarks":[{"id":3,                                                        +  "user_id":2,                                                                 +  "name":"Google",                                                             +  "url":"https://www.google.com"}, {"id":4,                                    +  "user_id":2,                                                                 +  "name":"Stack Overflow",                                                     +  "url":"http://stackoverflow.com/"}, {"id":5,                                 +  "user_id":2,                                                                 +  "name":"YouTube",                                                            +  "url":"https://www.youtube.com"}]}](1 row)

一开始使用它时可能有点不适应,但在需要更高性能时,在 PostgreSQL 中生成 JSON 是一个有用的功能。

号外!号外!号外!2022年PGfans核心用户点亮计划新鲜出炉啦!

期待各位创作者加盟,请点击下方链接观看更多精彩内容!

文章转载自开源软件联盟PostgreSQL分会,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论