2017-06-01 40 views
2

我使用的是9.6版。我有一個看起來是這樣的文件:如何選擇和更新PostgreSQL中JSON數組元素?

{ 
    "name" : "John Doe", 
    "phones" : [ 
     { 
      "type" : "mobile", 
      "number" : "555-555-0000", 
      "deleted": false 
     }, 
     { 
      "type" : "home", 
      "number" : "555-555-0001", 
      "needsUpdated" : true 
     }, 
     { 
      "type" : "work", 
      "number" : "555-555-0002" 
     } 
    ] 
} 

我創造了他們這樣的:

create table t_json (c_json json not null); 

insert into t_json (c_json) values ('{"name":"John Doe","phones": [{"type":"mobile","number":"555-555-0000"},{"type":"home","number":"555-555-0001"},{"type": "work","number": "555-555-0002"}]}'); 

insert into t_json (c_json) values ('{"name":"Jane Dane","phones": [{"type":"mobile","number":"555-555-0030"},{"type":"home","number":"555-555-0020"},{"type": "work","number": "555-555-0010"}]}'); 

現在,我試圖找出如何A,選擇具有名稱的行李四 ,並將他的手機號碼更新爲「555-555-0003」。

從這裏Postgresql 9.6 documentation我想通了,我可以像這樣適當的文檔查詢:

select c_json from t_json where c_json->>'name' = 'John Doe'; 

但我沒有看到如何在手機數組中的類型選擇合適的子文檔,並更新號碼值。誰能幫我嗎?

編輯

我需要承擔的子文檔有額外的價值和不一致。所以我在上面加了一些。我很確定,如果沒有數據丟失,此更新是不可能的。

+0

我想你使用jsonb_set這個 – maxymoo

+0

的可能的複製[如何修改新的PostgreSQL JSON數據類型裏面領域?](https://stackoverflow.com/questions/18209625/how-do-i-modify-fields-inside-the-new-postgresql-json-datatype) –

+0

@ JorgeCampos這不是重複的。我已經讀完了整個問題和每個答案,但沒有找到更新數組內子文檔的方法。不過謝謝。 –

回答

1

如何根據類型在手機數組中選擇合適的子文檔?

如果你想獲得的電話號碼,用這個。相應的文件是https://www.postgresql.org/docs/9.6/static/queries-table-expressions.html#QUERIES-LATERAL

SELECT c_json ->> 'name', phones.type, phones.number 
    FROM t_json 
    CROSS JOIN json_to_recordset(c_json -> 'phones') 
     AS phones("type" TEXT, "number" TEXT); 

如果你想通過電話號碼查詢,這個工程:

SELECT * FROM t_json 
    WHERE (c_json -> 'phones')::JSONB @> 
     '[{"type":"mobile","number":"555-555-0000"}]'::JSONB; 

如何更新的數值?

正如在註釋中,也有類似的問題,How do I modify fields inside the new PostgreSQL JSON datatype?

還有其他的方法來做到這一點,像

UPDATE t_json SET c_json = newvalue FROM (
    SELECT to_json(updated) AS newvalue FROM (
     SELECT c_json ->> 'name' as "name", 
      json_agg(json_build_object('type', phones.type, 'number', 
       CASE phones.type WHEN 'mobile' THEN '555-555-0003' ELSE phones.number END) 
      ) AS phones 
    FROM t_json 
    CROSS JOIN json_to_recordset(c_json -> 'phones') 
     AS phones("type" TEXT, "number" TEXT) 
    WHERE c_json->>'name' = 'John Doe' 
    GROUP BY name 
    ) as updated 
) AS sub WHERE c_json ->> 'name' = 'John Doe'; 
+0

哇,令人印象深刻的答案!謝謝你給我看看。這個問題是不是重複,我問具體如何更新陣列內的子文檔,我已經通過在評論認爲整個問題閱讀並沒有在任何地方,他們談論。它看起來對我來說,你的代碼片段實際上獲得了整個JSON對象,修改它並保存它背後,是正確的嗎?這酸符合? –

+0

是的,我展開整個JSON對象,並重建它。在一個SQL語句中,當然它符合ACID。 – crvv

+0

我是這麼認爲的,但我不喜歡承擔:)所以,你現在重新創建在json_agg子文件?值對,好比說「更新」:如果子文檔有一個額外的鍵會發生什麼「不」。除非將其添加到語句中,否則額外的數據將會丟失?還是我不正確的理解? –