如何更新Postgresql的Jsonb数组

如何更新Postgresql的Jsonb数组

假设你决定将数据以json或者jsonb的形式存储在数据库中,然后发现你刚刚给自己制造了新的问题,而这些问题是以前没有的。

jsonb是一个强大的工具,但它也有一定的代价,因为你需要调整查询和处理数据的方式。

而且将整个jsonb对象加载到内存中,用你喜欢的编程语言进行转换,然后将其保存回数据库,这并不罕见。但是,你刚刚创造了另一个问题:性能瓶颈和资源浪费。

在这篇文章中,我们来看看如何通过一次查询来更新数组内对象的特定值。

假设你正在实现一个为每个客户存储动态联系人功能,那么你就会想到将联系人存储为jsonb列,因为他们是动态的,因此使用非关系型数据结构是有意义的。

然后创建一个带有jsonb列联系人,并在其中插入一些数据。

create table customers (name varchar(256), contacts jsonb);insert into customers (name, contacts) values ('Jimi','[{"type": "phone", "value": "+1-202-555-0105"},{"type": "email", "value": "jimi@gmail.com"}]'
);insert into customers (name, contacts) values ('Janis','[{"type": "email", "value": "janis@gmail.com"}]'
);

看起来很简单,但是如何更新特定的联系人信息?如何更改jimi的电子邮件或者janis的电话?

幸运的是,PostgreSQL提供了json_set函数。函数原型:

jsonb_set(target jsonb, path text[], new_value jsonb[, create_missing boolean])

给定一个jsonb列,可以在指定的路径上设置一个新值。

select jsonb_set('[{"type": "phone", "value": "+1-202-555-0105"},{"type": "email", "value": "jimi@gmail.com"}]','{1,value}','"jimi.hendrix@gmail.com"',false
);select jsonb_set('[{"type": "email", "value": "janis@gmail.com"}]','{0,value}','"janis.joplin@gmail.com"',false
);

jsonb_set函数的第一个参数为jsonb数据对象,第二个参数路径,在上面的例子中,{1,value}为数组中索引为1的元素,并且属性是value字段的,最后一个参数是对路径中选择的字段进行赋值。

根据这样的规则,那么第一个sql语句就是修改jimi的邮箱,而第二个sql语句就是修改janis的电子邮箱。

上面返回的结果是:

[{"type":"phone","value":"+1-202-555-0105"},{"type":"email","value":"jimi.hendrix@gmail.com"}]
[{"type":"email","value":"janis.joplin@gmail.com"}]

如果现在你认为这样就完事了,那就是你太Too young! Too simple!

非关系型数据库的问题在于它们是动态的,这也是使用jsonb的原因之一,但是这就带来了一个问题,例如上面的案例,jimi的邮箱对象在数组中的索引是1,janis的邮箱对象在数组中索引是0,而另外的一条数据很可能是不同的数组,其索引也不一样,那么如何确定每个联系人的邮箱所在数组的索引?

答案 是对数组中的元素进行排序,并获得索引。

select index-1 as indexfrom customers,jsonb_array_elements(contacts) with ordinality arr(contact, index)where contact->>'type' = 'email'and name = 'Jimi';

该查询会返回1,这是jimi联系人的电子邮件对象索引。

现在万事俱备,只欠东风!我们把查询和更改步骤合并。

with contact_email as (select ('{'||index-1||',value}')::text[] as pathfrom customers,jsonb_array_elements(contacts) with ordinality arr(contact, index)where contact->>'type' = 'email'and name = 'Jimi'
)
update customersset contacts = jsonb_set(contacts, contact_email.path, '"jimi.hendrix@gmail.com"', false)from contact_emailwhere name = 'Jimi';

这个sql中最重要的部分就是with,这是一个强大的命令,但对于这个例子来说,你可以把它看成是“储存变量”功能,with最后的结果都储存在contact_email变量内,其中就包含需要更新的路径,也就是jimi的邮箱路径。

下面再稍微详细介绍一下:

(‘{‘||index-1||’,value}’)::text[] as path

这一段是在建立路径{1, value},但是要转换成text[]类型,因为jsonb_set函数需要这个类型。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/535971.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

golang操作postgresql数据库jsonb类型

golang操作postgresql数据库jsonb类型 本文以案例为主,少言,自悟。 推荐一个测试sql的网站 SQL操作 // 创建一个带有jsonb列的表 CREATE TABLE items (id SERIAL PRIMARY KEY,attrs JSONB );// 插入一条数据 INSERT INTO items (attrs)

Angular模板高级使用

Angular模板高级使用 使用ng-template Angular自带一个叫做ng-template的组件,它允许我们声明Angular模板的任何部分。这是给我们的模板赋予动态性的一种很好的方式,让我们能够把我们的代码传递给其他组件。 在app.component.html文件中写一个ng-template组件。 <ng-t…

golang定时任务的使用

golang定时任务的使用 由于 golang 标准库内没有比较好的定时任务包,所以这里将使用一个第三方的 cron 包,由于此包存在一些不适用的地方,所以对此做了一些简单封装。 cron简介 robfig/cron是一个第三方开源的任务调度库,也就是我们平时说的定时任务。 Github官方文档安…

go之树型结构深度理解

go之树型结构深度理解 如果你是一个编程人员,或多或少对树型结构都有一定的认识,我个人对树型数据结构是又爱又恨。这篇文章主要讲解一些关于tree的数据结构以及使用。 什么是树? 数组、列表、队列、队列、堆栈都是以一个集合的形式存储数据,一般称它们被称为 "线性…

go之树型结构深度理解补充

go之树型结构深度理解补充 在上一篇中借用了 Ilija Eftimov 文章来讲解了tree的定义和一些方法。这篇文章主要是讲解在树型结构中如何判断节点与节点之间的关系。 A节点是否是B节点的直接上级A节点是否是B节点的可跳跃的上级(即中间隔开几个节点的间接上级)上一篇文章连接 g…

golang之jsonb类型的支持

golang之jsonb类型的支持 jsonb是一个很好的存储方式,可以省去我们很多的数据库复杂设计,简化架构。那么我们在golang中如何使用? 当然我们是不能直接使用的,所以这篇文章将指导你在golang中如何正确的使用jsonb。 场景 我们希望在应用程序中处理这种实体。 {id: …

Go信号gsignal和宿主Signal

信号gsignal和宿主Signal signal包提供了信号处理程序,并允许我们的Go程序与输入的信号进行交互。 订阅 信号的订阅是通过channel来完成的,下面是一个例子,功能是监听任何终端信号或者终端退出的信号。 每个os.Signal通道监听自己的事件。 Go还提供了停止通知通道的功能,…

Angular实现图片点击缩放组件

Angular实现图片点击缩放组件 本文将设计一个用于网页中点击图片缩放的 Angular 组件。阅读需要注意的是,本文只讲解原理和设计理念,不过多讲解Angular框架的API。 线demo。 需求分析 一般用户在阅读文章的时候,由于种种限制,图片会比较小,所以需要提供一个可以查看图…

Angular动态创建组件

Angular动态创建组件 什么是动态创建? 一般来说就是组件不需要在html内定义,而是通过typescript来控制该组件的创建。往往我们大部分的时候都是在html内定义,之所以这样也能够创建出我们想要的组件,这是因为Angular框架在编译后或运行时会帮助我们创建这个组件并生成相应…

Angular实现灵活的动态创建组件指令

Angular实现灵活的动态创建组件指令 在某些场景下需要动态创建指令,但是不想每次都要写很多重复的代码,那么封装一个灵活的指令是比较好的方式。 本文代码库已经在github上 ngx-dyncmp stackblitz示例连接 最终目标 设计之前需要设想需要做成什么样子,支持哪些特性,下…

Vscode Todo Tree插件

Vscode Todo Tree插件 安装 打开 vscode 扩展中心&#xff0c;搜索 todo tree 然后安装&#xff0c; 配置 打开vscode设置&#xff0c;文件→首选项→设置&#xff0c;然后以json文件打开&#xff0c;并增加以下配置 "todo-tree.highlights.customHighlight": {&…

Albert launcher安装与使用

Albert launcher安装与使用 安装 安装系统为: linuxmint 20 打开终端执行&#xff1a; curl https://build.opensuse.org/projects/home:manuelschneid3r/public_key | sudo apt-key add - echo deb http://download.opensuse.org/repositories/home:/manuelschneid3r/xUbu…

golang cobra powershell补全脚本

golang cobra powershell补全脚本 cobra 对于windows我个人觉得支持不是很好,所以写了下面的脚本,无论你怎么修改cobra都可以自适应补全命令。 原理就是使用cobra隐藏命令:__completeNoDesc 开启补全支持 由于powershell目前还处于不是很完善的阶段,需要一定的设置才可以…

Linuxmint 美化之路

经过无数次的实验&#xff0c;最终配置了一套比较舒服的主题&#xff0c;审美在不断的提高&#xff0c;但是内在快跟不上了哈 1. 安装主题 先下载资源包&#xff0c;资源包是收费的&#xff0c;算是犒赏吧。 https://download.csdn.net/download/wf19930209/23520618 1.1 更…

初识 Arm 处理器

英国ARM公司是全球领先的半导体知识产权&#xff08;IP&#xff09;提供商。全世界超过95%的智能手机和平板电脑都采用ARM架构。ARM设计了大量高性价比、耗能低的RISC处理器、相关技术及软件。2014年基于ARM技术的全年全球出货量是120亿颗&#xff0c;从诞生到现在为止基于ARM技…

模拟神器之QEMU

1. 简介 QEMU&#xff08;quick emulator&#xff09;是一款由法布里斯贝拉&#xff08;Fabrice Bellard&#xff09;等人编写的免费的可执行硬件虚拟化的&#xff08;hardware virtualization&#xff09;开源托管虚拟机&#xff08;VMM&#xff09;。 QEMU 是一个托管的虚拟…

X86_64平台运行Arm docker容器

QEMU是什么 QEMU是一个通用的开源的跨平台仿真模拟器&#xff0c;提供user和system两种模式。其模拟的作用可是可以模拟在特定的体系结构下的应用的执行或者构建&#xff0c;比如在x86的体系结构的操作系统上运行ARM的应用。 常见问题的场景 在ARM体系结构的硬件环境中安装D…

Go 条件编译

接触过C/C++编程的应该一定知道条件编译。通常为了满足不同环境下使用不同的代码,从而在编译的时候进行选择性的编译,达到最佳的泛用性。 例如: #define WINDOWS #ifdef WINDOWS # include <windows.h> #elif defined LINUX # include <sys/types.h> # includ…

Boost Arm 交叉编译

Boost Arm 交叉编译 1. 源码下载 下载地址&#xff1a;https://sourceforge.net/projects/boost/files/boost/ 这里下载 1.74.0 版本 然后解压。 2. 配置 有些库我们是不需要的&#xff0c;所以就不需要编译&#xff0c;可以通过 -show-libraries 查看库列表 vincentmsi-…

为什么Linux会开机黑屏?

有的童鞋由于工作的需要&#xff0c;或者想体验一把无广告的世界&#xff0c;会去尝试使用Linux的发行版&#xff0c;但是经常被Linux拒之门外&#xff0c;甚至连系统到装不上&#xff0c;当然这个现象也在越来越少&#xff0c;只有更多的人去使用它&#xff0c;它才会变的更好…