簡體   English   中英

使用 jsonb_set() 進行條件更新

[英]Conditional update with jsonb_set()

我在 Postgres 11.3 數據庫中有一個jsonb列的表。

嘗試更新嵌套數組名稱"iProps"中的所有對象。

如果路徑{iProps -> value -> rules -> ao -> sc}是 object,則應該將路徑從 object 更新為值為{iProps -> value -> rules -> ao -> sc -> name}的字符串{iProps -> value -> rules -> ao -> sc -> name}

如果路徑{iProps -> value -> rules -> ao -> sc}不存在,則 object 應保持不變。

帶有查詢的測試設置: 小提琴鏈接

期望的結果:

{
    "iProps": [
        {
            "value": {
                "rules": [
                    {
                        "ao": {
                            "set": "get"
                        },
                        "name": "PRule"
                    },
                    {
                        "ao": {
                            "sc":  "name1"
                            
                        }
                    },
                    {
                        "ao": {
                            "sc": "name2"
                            
                        }
                    },
                    {
                        "ao": {
                            "sc":  "name3"                            
                        }
                    }
                ]
            }
        }
    ]
}

我已經修改了查詢並在小提琴中鏈接。 有人可以看看是否正確嗎?

一個普通的CASE應該有所作為。

UPDATE table_ t
SET    value_ = jsonb_set(value_, '{iProps}', sub2.new_prop, false)
FROM  (
   SELECT id
        , jsonb_agg(jsonb_set(prop, '{value, rules}', new_rules, false)
                    ORDER BY idx1) AS new_prop
   FROM  (
      SELECT t.id, arr1.prop, arr1.idx1
           , jsonb_agg(CASE WHEN jsonb_typeof(rule #> '{ao,sc}') = 'object' THEN jsonb_set(rule, '{ao,sc}', rule #> '{ao,sc,name}', false) ELSE rule END
                       ORDER BY idx2) AS new_rules
      FROM table_ t
         , jsonb_array_elements(value_->'iProps')       WITH ORDINALITY arr1(prop,idx1)
         , jsonb_array_elements(prop->'value'->'rules') WITH ORDINALITY arr2(rule,idx2)
      GROUP  BY t.id, arr1.prop, arr1.idx1
      ) sub1
   GROUP  BY id
   ) sub2
WHERE t.id = sub2.id;

db<>fiddle here (Postgres 11!)

要同時滿足您在更新中添加的第二個過濾器(必須是object ),請使用jsonb_typeof()進行檢查。

您小提琴中的查詢似乎不必要地復雜(tl; dr)。 此外,它不保留數組元素的原始順序 如果這實際上無關緊要,請省略WITH ORDINALITYORDER BY並進一步簡化:

UPDATE table_ t
SET    value_ = jsonb_set(value_, '{iProps}', sub2.new_prop, false)
FROM  (
   SELECT id
        , jsonb_agg(jsonb_set(prop, '{value, rules}', new_rules, false)) AS new_prop
   FROM  (
      SELECT t.id, prop
           , jsonb_agg(CASE WHEN jsonb_typeof(rule #> '{ao,sc}') = 'object'
                            THEN jsonb_set(rule, '{ao,sc}', rule #> '{ao,sc,name}', false)
                            ELSE rule
                       END) AS new_rules
      FROM table_ t
         , jsonb_array_elements(value_->'iProps')       prop
         , jsonb_array_elements(prop->'value'->'rules') rule
      GROUP  BY t.id, prop
      ) sub1
   GROUP  BY id
   ) sub2
WHERE t.id = sub2.id;

db<> 在這里擺弄

這通常仍然保留數組元素的順序(與您的原始元素不同)。 只是不能保證有兩個聚合級別。

看:

我對您之前相關問題的回答中的更多建議:

暫無
暫無

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

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