Postgresql Json

最近有个功能,需要用到 NoSQL 数据库。但是又不想因为这个小小的功能给系统增加一个 MongoDB 数据库,于是就想到了 Postgresql 支持 JSON 类型的数据格式,可以用来实现类似 NoSQL 数据库的功能。于是研究了一下。

版本说明:

Postgresql Version : 12

Linux Virtual Machine: Ubuntu 22.04 4G 2Cpu

数据类型

JSON 和 JSONB 区别

Postgresql 从 9.2 版本开始支持 json 数据类型,从 9.4 开始支持 jsonb 数据类型。

区别:

  • json 类型是将整个json字符进行完成保存,包括空格、重复的键、和键的顺序等。
  • jsonb 类型会对json字符进行解析后保存二进制,解析的时候会删除不必要的空格和重复的键等。

由于上面的区别,所以在储存的时候 json 会比 jsonb 快,毕竟少了一个解析的步骤。但是在查询的时候 json 会比 jsonb 慢。

由于 jsonb 是格式化后的数据,所以他能使用的函数比 json 多很多,jsonb 甚至能使用索引。(具体使用哪种类型就要根据具体的业务场景了)

注意:这两者在储存的时候,字符串都要符合json规范,要不会储存失败。

JSON 和 JSONB 测试

创建一个表格,实验一下。

  1. -- 创建一个 json_test_table
  2. -- json_data josn 类型
  3. -- jsonb_data jsonb 类型
  4. CREATE TABLE "json_test_table" (
  5. "id" int4 PRIMARY KEY,
  6. "json_data" json,
  7. "jsonb_data" jsonb
  8. )

向表里插入一条数据

  1. -- 这里注意一下两个 json 对象都有一个相同的键'name'
  2. INSERT INTO
  3. json_test_table(id,json_data,jsonb_data)
  4. VALUES(
  5. 1,
  6. '{
  7. "name":"zhangsan",
  8. "name":"zhangsan",
  9. "age":18,
  10. "isBoy":true
  11. }
  12. '::json,
  13. '
  14. {
  15. "name":"lisi",
  16. "name":"lisi1",
  17. "age":22,
  18. "isBoy":false
  19. }
  20. '::jsonb
  21. )

把刚才的数据查出来

  1. SELECT * FROM json_test_table
  1. id | json_data | jsonb_data
  2. --------------------------------------------------------------------------------------------------------------
  3. 1 | {"name":"zhangsan","name":"zhangsan","age":18,"isBoy":true } | {"age": 22, "name": "lisi1", "isBoy": false}

查询结果中 jsonb_data 中只保留了一个 name 并且键的顺序也改变了(这里没体现出来json_data也保留了空格等字符,可以自己写个sql测一下)。

使用 JSONB 类型

由于本次功能读多写少,所以这里主要研究一下 jsonb 的增删改查的功能,其实 josn 类型也差不多。

增加

新增一条 josnb_data 就使用普通的 insert sql 就行。

  1. INSERT INTO
  2. json_test_table(id,jsonb_data)
  3. VALUES(
  4. 2,
  5. '
  6. {
  7. "name":"lisi",
  8. "age":22,
  9. "isBoy":false
  10. }
  11. '
  12. )

上面我们在表中新增了行数据,现在再往 jsonb_data 中再新增一个键 "address_path" 他是一个字符串数组,值为 ["中国","江苏"]

  1. -- 其实这里只是调用 jsonb_set 方法把 jsonb 修改后,一个 UPDATE 操作把数据更新了。
  2. UPDATE
  3. json_test_table
  4. SET
  5. jsonb_data = jsonb_set(jsonb_data, '{address_path}', '["中国","江苏"]')
  6. WHERE
  7. id = 2

更新后数据变成了

  1. id | jsonb_data
  2. --------------------------------------------------------------------------------------------------------------
  3. 1 | {"age": 22, "name": "lisi", "isBoy": false, "address_path": ["中国", "江苏"]}

jsonb_set ( target, path, new_value [, create_if_missing ] )

  • target:需要修改的json数据。
  • path:要修改的值的路径。如果target是数组'{0,a}'表示在下标是0的位置更新a属性,如果是对象,则写'{a}'则会修改"a"键的内容。
  • create_if_missing:当不存在 path 指定的键是否新建一个,默认是 true。

本质上对 jsonb 的增删改等操作就是 UPDATE 语句把表中的原数据更新掉。只是对 jsonb 对象的修改交给了数据库,这样压力就给到数据库服务。你完全可以把整条数据查出来,然后用业务逻辑处理后再调用 UPDATE 回去,但是这样压力就到了业务服务上,而且每次数据传输也会消耗时间。

除了使用上面的 jsonb_set 也可以使用 || 操作符。

  1. UPDATE
  2. json_test_table
  3. SET
  4. jsonb_data = jsonb_data || '{"address_path":["中国","江苏"]}'
  5. WHERE
  6. id = 2

查找

查找某个键的值

如果我们不想把整个 jsonb_data 都查出来,只想查找其中某几个键值。

  1. SELECT jsonb_data::json ->> 'name',jsonb_data::json ->> 'age' as ageFROM json_test_table WHERE id = 2

返回

  1. name | age |
  2. ------------
  3. lisi | 22 |

如果是数组的对象应该怎么查呢?

我们在添加一列用于测试数组

  1. id | jsonb_arr_data
  2. --------------------------------------------------------------------------------------------------------------
  3. 2 | [{"id": 1, "value": "value1"}, {"id": 2, "value": "value2"}, {"id": 3, "value": "value3"}]

先来看一下一个方法 jsonb_array_elements 。他的作用就是 JSON数组展开为一组JSON值.

  1. SELECT jsonb_array_elements(jsonb_arr_data) FROM json_test_table WHERE id = 2
  1. jsonb_array_elements |
  2. ----------------------------
  3. {"id": 1, "value": "value1"}|
  4. {"id": 2, "value": "value2"}|
  5. {"id": 3, "value": "value3"}|

所以只想查出 id 是 1 的值可以这么写

  1. SELECT D FROM json_test_table T,jsonb_array_elements(jsonb_arr_data) D WHERE id = 2 AND D::json ->> 'id' = '1'
  1. d |
  2. ----------------------------
  3. {"id": 1, "value": "value1"}|

所以只想查出 id 是 1 和 2 的值可以这么写


  1. SELECT D FROM json_test_table T,jsonb_array_elements(jsonb_arr_data) D WHERE id = 2 AND D::json ->> 'id' in ('1','2')
  1. d |
  2. ----------------------------
  3. {"id": 1, "value": "value1"}|
  4. {"id": 2, "value": "value2"}|

删除

删除刚才添加的 "address_path"

  1. UPDATE
  2. json_test_table
  3. SET
  4. jsonb_data = jsonb_data - 'address_path'
  5. WHERE
  6. id = 2

参考

Postgresql Release 9.2,by postgresql.org

Postgresql Release 9.4,by postgresql.org

Postgresql JSON Functions and Operators,by postgresql.org

PostgreSQL JSON 函数和操作符,by w3cschool.cn

Postgresql——jsonb类型的更多相关文章

  1. postgresql jsonb类型查询

    select * from (select * from ud_order where user_id=10 and status=2unionselect * from ud_order where ...

  2. PostgreSQL 数组类型使用详解

    PostgreSQL 数组类型使用详解 PostgreSQL 数组类型使用详解 可能大家对 PostgreSQL 这个关系型数据库不太熟悉,因为大部分人最熟悉的,公司用的最多的是 MySQL 我们先对 ...

  3. PostgreSQL 保存json,jsonb类型

    PostgresQL 字符串隐式转换JSON脚本: -- 隐式将varchar转换为json CREATE OR REPLACE FUNCTION json_in_varchar(varchar) R ...

  4. postgresql ltree类型

    最近一个月使用Postgresql的时候,经常遇到ltree的数据,感觉有些别扭,可是有绕不过去.今天决心整理一下,以后使用方便一些. 一.简介 ltree是Postgresql的一个扩展类型,由两位 ...

  5. PostgreSQL 数组类型

    PostgreSQL 支持表的字段使用定长或可变长度的一维或多维数组,数组的类型可以是任何数据库内建的类型.用户自定义的类型.枚举类型, 以及组合类型.但目前还不支持 domain 类型. 数组类型的 ...

  6. PostgreSQL TIMESTAMP类型 时间戳

    PostgreSQL 提供两种存储时间戳的数据类型: 不带时区的 TIMESTAMP 和带时区的 TIMESTAMPTZ. TIMESTAMP 数据类型可以同时存储日期和时间,但它不存储时区.这意味着 ...

  7. postgresql数字类型

    postgresql的数据类型很多,也可以使用create type命令创建自定义数据类型,但常用的数据类型是以下三种: l  数字数据类型 l  字符串数据类型 l  日期/时间数据类型 数字数据类 ...

  8. PostgreSQL数组类型应用

    在使用 awk 脚本:数组是一大利器:在很多场景是用数组能处理. 在 python 中,数据类型list:相当于array类型. 在 Oracle 中,对 array 不够友好,感觉像是鸡肋.但是在 ...

  9. Postgresql Jsonb字段内含数组属性的删除元素操作

    1.创建示例表 create temp table settings as select '{"west": [ {}, {} ]}'::jsonb as value; 2.如下保 ...

  10. PostgreSQL字段类型说明

    BIGSERIALSERIAL8 存储自动递增的惟一整数,最多 8 字节. BIT 固定长度的位串. BIT VARYING(n)VARBIT(n) 可变长度的位串,长度为 n 位. BOOLEAN  ...

随机推荐

  1. 代码随想录算法训练营第四天| LeetCode 24. 两两交换链表中的节点 19.删除链表的倒数第N个节点 142.环形链表II

    24. 两两交换链表中的节点         卡哥建议:用虚拟头结点,这样会方便很多. 本题链表操作就比较复杂了,建议大家先看视频,视频里我讲解了注意事项,为什么需要temp保存临时节点. 题目链接/ ...

  2. 线性关系和非线性关系在.net中的应用

    在数学中,线性关系和非线性关系是描述两个变量之间函数关系的两种不同类型. 线性关系是指两个变量之间可以用一条直线来表示的关系.具体来说,如果存在一个一次函数 y = kx + b,其中k和b是常数,使 ...

  3. 【Azure App Service】为部署在App Service上的PHP应用开启JIT编译器

    问题描述 在App Service for linux上创建一个PHP应用,通过 phpinfo() 查看PHP的扩展设置,发现JIT没有被开启, jit_buffer_size 大小为0. 那么,在 ...

  4. c# .NET 高级编程 高并发必备技巧 - 锁

    锁 最为常见的应用就是 高并发的情况下,库存的控制.本次只做简单的单机锁介绍. 直接看代码: 每请求一次库存-1. 假如库存1000,在1000个人请求之后,库存将变为0. public int Re ...

  5. Python 基础面试第二弹

    1. 解释下Python中的面向对象,以及面向对象的三大特点: 在Python中,面向对象编程(Object-Oriented Programming,简称OOP)是一种编程范式,它将数据和操作数据的 ...

  6. 深入理解Linux内核——内存管理(3)

    提要:本系列文章主要参考MIT 6.828课程以及两本书籍<深入理解Linux内核> <深入Linux内核架构>对Linux内核内容进行总结. 内存管理的实现覆盖了多个领域: ...

  7. Elasticsearch之索引简单应用

    本篇所有操作都在 Kibana 上执行 创建第一个索引 PUT product { // 索引设置 "settings": { // 分片数量 "number_of_sh ...

  8. Dubbo3应用开发—XML形式的Dubbo应用开发和SpringBoot整合Dubbo开发

    Dubbo3程序的初步开发 Dubbo3升级的核心内容 易⽤性 开箱即⽤,易⽤性⾼,如 Java 版本的⾯向接⼝代理特性能实现本地透明调⽤功能丰富,基于原⽣库或轻量扩展即可实现绝⼤多数的 微服务治理能 ...

  9. 「atcoder - agc054c」Roughly Sorted

    link. 高妙题,我只会到构造下界那一步-- 构造下界比较容易,只需要注意到交换一次最多让序列向合法迫近一步即可.则答案下界为 \(\sum_i \max\{\left(\sum_{j < i ...

  10. Note -「SOS DP」高维前缀和

    本文差不多算是翻译了一遍 CF blog?id=45223 就是抄了一遍,看不懂可以去原文. 当然我的翻译并不是完全遵从原文的. Part. 1 Introduction 平时我们怎么求高维前缀和?容 ...