如何更新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.pswp.cn/news/535971.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/535971.shtml
英文地址,請注明出處:http://en.pswp.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;它才會變的更好…