PostgreSQL 9.2 版本引入Json作为基本类型,它可以存储json对象,使得PostgreSQL 支持无Schema的NoSQL特性。PostgreSQL 9.4 有加入了jsonb 类型,本文带你了解jsonb类型,并通过示例学习相关操作。

JSONB类型

json类型以文本方式存储json对象,所以每次处理时需要解析和分析文本格式的json。另外还存储了不必要的空白字符和重复键。jsonb类型转换文本格式json对象未二进制格式,并删除了不需要的白色空格及重复键。因为有了预处理,jsonb需要更多空间和处理能力,但对jsonb的处理会更有效。当然所有json的操作都支持,而且还支持gin类型索引。

示例

创建数据库并填充示例数据:

CREATE TABLE books (
  id SERIAL PRIMARY KEY,
  client TEXT NOT NULL,
  data JSONb NOT NULL
);

INSERT INTO books(client, data) values ( 'Joe', 
    '{ "title": "Siddhartha", "author": { "first_name": "Herman", "last_name": "Hesse" } }'
),( 'Jenny', 
    '{ "title": "Dharma Bums", "author": { "first_name": "Jack", "last_name": "Kerouac" } }'
),( 'Jenny', 
    '{ "title": "100 años de soledad", "author": { "first_name": "Gabo", "last_name": "Marquéz" } }'
);

SELECT * FROM books;

返回结果:

idclientdata
1Joe{“title”: “Siddhartha”, “author”: {“last_name”: “Hesse”, “first_name”: “Herman”}}
2Jenny{“title”: “Dharma Bums”, “author”: {“last_name”: “Kerouac”, “first_name”: “Jack”}}
3Jenny{“title”: “100 años de soledad”, “author”: {“last_name”: “Marquéz”, “first_name”: “Gabo”}}

-> ->> 操作

首先看 -> :

SELECT client, 
   data->'title' AS title, data->'author' AS author
   FROM books;	
clienttitleauthor
Joe“Siddhartha”{“last_name”: “Hesse”, “first_name”: “Herman”}
Jenny“Dharma Bums”{“last_name”: “Kerouac”, “first_name”: “Jack”}
Jenny“100 años de soledad”{“last_name”: “Marquéz”, “first_name”: “Gabo”}

再通过 ->>操作对比:

SELECT client, 
   data->>'title' AS title, data->'author'->>'first_name' AS author
   FROM books;
clienttitleauthor
JoeSiddharthaHerman
JennyDharma BumsJack
Jenny100 años de soledadGabo

->返回json对象, ->> 返回文本值。

过滤操作

 SELECT  client, data->>'title' AS title
 FROM books
 WHERE data->>'title' = 'Dharma Bums';

返回结果:

clienttitle
JennyDharma Bums

嵌套过滤

SELECT  client, data->>'title' AS title
FROM books
WHERE data->'author'->>'last_name' = 'Kerouac';

返回结果:

clienttitle
JennyDharma Bums

实战案例

CREATE TABLE events (
  name varchar(200),
  visitor_id varchar(200),
  properties json,
  browser json
);

假如我们存入页面浏览的事件,每个事件有属性,如当前页面、也包括客户端信息(如,操作系统,屏幕分辨率等)。因为没有schema限制,可以存储任意内容。

载入示例数据:

INSERT INTO events (name, visitor_id, properties, browser) VALUES
(
  'pageview', '1',
  '{ "page": "/" }',
  '{ "name": "Chrome", "os": "Mac", "resolution": { "x": 1440, "y": 900 } }'
),(
  'pageview', '2',
  '{ "page": "/" }',
  '{ "name": "Firefox", "os": "Windows", "resolution": { "x": 1920, "y": 1200 } }'
),(
  'pageview', '1',
  '{ "page": "/account" }',
  '{ "name": "Chrome", "os": "Mac", "resolution": { "x": 1440, "y": 900 } }'
),(
  'purchase', '5',
  '{ "amount": 10 }',
  '{ "name": "Firefox", "os": "Windows", "resolution": { "x": 1024, "y": 768 } }'
),(
  'purchase', '15',
  '{ "amount": 200 }',
  '{ "name": "Firefox", "os": "Windows", "resolution": { "x": 1280, "y": 800 } }'
),(
  'purchase', '15',
  '{ "amount": 500 }',
  '{ "name": "Firefox", "os": "Windows", "resolution": { "x": 1280, "y": 800 } }'
);
-- 验证结果
select * from events;

结果如下:

namevisitor_idpropertiesbrowser
pageview1{ “page”: “/” }{ “name”: “Chrome”, “os”: “Mac”, “resolution”: { “x”: 1440, “y”: 900 } }
pageview2{ “page”: “/” }{ “name”: “Firefox”, “os”: “Windows”, “resolution”: { “x”: 1920, “y”: 1200 } }
pageview1{ “page”: “/account” }{ “name”: “Chrome”, “os”: “Mac”, “resolution”: { “x”: 1440, “y”: 900 } }
purchase5{ “amount”: 10 }{ “name”: “Firefox”, “os”: “Windows”, “resolution”: { “x”: 1024, “y”: 768 } }
purchase15{ “amount”: 200 }{ “name”: “Firefox”, “os”: “Windows”, “resolution”: { “x”: 1280, “y”: 800 } }
purchase15{ “amount”: 500 }{ “name”: “Firefox”, “os”: “Windows”, “resolution”: { “x”: 1280, “y”: 800 } }

使用聚集函数

json 操作可以和传统的聚集函数一期使用。下面示例统计浏览器类型:

  SELECT browser->>'name' AS browser, 
    count(browser)
    FROM events
    GROUP BY browser->>'name';
browsercount
Chrome2
Firefox4
  • 统计访问者:
  SELECT visitor_id, SUM(CAST(properties->>'amount' AS integer)) AS total
  FROM events
  WHERE CAST(properties->>'amount' AS integer) > 0
  GROUP BY visitor_id;

返回结果:

visitor_idtotal
15700
510
  • 屏幕分辨率平均值
  SELECT round(AVG(CAST(browser->'resolution'->>'x' AS integer)),2) AS width,
         round(AVG(CAST(browser->'resolution'->>'y' AS integer)),2) AS height
  FROM events;

返回结果:

widthheight
1397.33894.67

总结

本文带你学习了PostgreSQL的jsonb类型,主要通过示例展示如何查询json的属性值,并和聚集函数一起使用。另外也可以对jsonb类型的属性进行增加、修改、删除等操作,读者可以查阅相关文档进一步学习。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐