簡體   English   中英

在 Postgres 中使用約束更新 jsonb 數組值

[英]Updating a jsonb array value with constraints in Postgres

我有一個帶有數組的jsonb類型的表,我正在嘗試在該數組中專門散列/匿名化遵循某些要求的電子郵件(通過 md5 或 sha1)。 使用下面的虛擬數據,我很難嘗試專門針對沒有@google.comadmin的任何電子郵件的owners數組。

{
    "blah": blah,
    "owners": [
        "admin"
    ],
},
{
    "blah": blah,
    "owners": [
        "john@google.com"
    ],
},
{
    "blah": blah,
    "owners": [
        "jason@facebook.com", "fred@facebook.com"
    ],
},
{
    "blah": blah,
    "owners": [
        "zuck@facebook.com", "bill@google.com"
    ],
}

理想情況下,最終結果應該是

{
    "blah": blah,
    "owners": [
        "admin"
    ],
},
{
    "blah": blah,
    "owners": [
        "john@google.com"
    ],
},
{
    "blah": blah,
    "owners": [
        "dskfjld@hashed.com", "dshfjkdhsfjk@hashed.com"
    ],
},
{
    "blah": blah,
    "owners": [
        "hashfsdflksdjf@hashed.com", "bill@google.com"
    ],
}

這里的邏輯可能是遍歷列中的每個owners數組,但不確定查詢的具體外觀。

(a) 您的jsonb數據樣本內部有一些錯誤。 對於這個答案,我將改用:

[{
    "blah": "blah",
    "owners": [
        "admin"
    ]},
{
    "blah": "blah",
    "owners": [
        "john@google.com"
    ]},
{
    "blah": "blah",
    "owners": [
        "jason@facebook.com", "fred@facebook.com"
    ]},
{
    "blah": "blah",
    "owners": [
        "zuck@facebook.com", "bill@google.com"
    ]}]

(b) 使用 postgres 在jsonb數據中進行多次更新並不容易。 以下解決方案在使用新的 email 值更新 jsonb 數據結構時跟蹤路徑信息時分解 jsonb 數據結構。

(c) 該解決方案基於jsonb_set()標准 function,它只能對給定的 jsonb 數據應用一次更新。 所以第一步是創建 function jsonb_set_agg()作為基於jsonb_setaggregate ,它能夠在迭代一組記錄時對相同的 jsonb 數據執行多次更新:

CREATE OR REPLACE FUNCTION jsonb_set(x jsonb, y jsonb, p text[], z jsonb, c boolean)
RETURNS jsonb LANGUAGE sql AS
$$ SELECT jsonb_set(COALESCE(x,y), p, z, c) ; $$ ;

CREATE OR REPLACE AGGREGATE jsonb_set_agg(x jsonb,p text[], z jsonb, c boolean)
(SFUNC = jsonb_set, STYPE = jsonb) ;

(d) 最后,以下查詢分解 jsonb 數據( FROM子句),過濾必須更新的電子郵件( WHERE子句),然后根據基於ORDINALITY的路徑,用新的 email 值更新 jsonb 數據信息:

SELECT jsonb_set_agg(j.json_data, array[(b.id - 1) :: text, 'owners', (c.id - 1) :: text], to_jsonb('insert_here_the_new_value' :: text), true)
  FROM (VALUES ('[{
    "blah": "blah",
    "owners": [
        "admin"
    ]},
{
    "blah": "blah",
    "owners": [
        "john@google.com"
    ]},
{
    "blah": "blah",
    "owners": [
        "jason@facebook.com", "fred@facebook.com"
    ]},
{
    "blah": "blah",
    "owners": [
        "zuck@facebook.com", "bill@google.com"
    ]}]' :: jsonb)) AS j(json_data)
 CROSS JOIN LATERAL jsonb_array_elements(j.json_data) WITH ORDINALITY AS b(json_data, id)
 CROSS JOIN LATERAL jsonb_array_elements_text(b.json_data->'owners') WITH ORDINALITY AS c(json_data, id)
 WHERE c.json_data <> 'admin'
   AND NOT c.json_data ~ '@google.com$'

結果是:

[ {"blah": "blah", "owners": ["admin"]}
, {"blah": "blah", "owners": ["john@google.com"]}
, {"blah": "blah", "owners": ["insert_here_the_new_value","insert_here_the_new_value"]}
, {"blah": "blah", "owners": ["insert_here_the_new_value", "bill@google.com"]}
]

dbfiddle中的所有詳細信息。

您可以使用帶有json_agg的子查詢:

select jsonb_set(t.data, '{owners}', 
   (select jsonb_agg(case when v.value::text = '"admin"' or v.value::text  ~ 'google\.com"' then v.value::text else md5(substring(v.value::text from '^"(\w+)@'))||'@'||md5(substring(v.value::text from '@(\w+\.\w+)"$')) end) 
   from jsonb_array_elements(t.data -> 'owners') v)) 
from vals t

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM