Postgres - 更新和重构JSONB类型列的属性

时间:2017-11-17 22:02:34

标签: postgresql postgresql-9.4 jsonb

我有一个表,其中有一个名为“data”的列,类型为JSONB。我正在尝试根据最近的模型更改创建迁移脚本。 (postgres 9.4)

“gstNotRegisteredReason”, “gstRegistered”, “isIndiaGSTComposition” 在旧模型中需要在新模型中更改为“vatExemptionReason”,“vatExemption”,“auxiliaryProperties”

旧模型:

 {  
   "requestId":531956,
   "requestVersion":5,
   "supplier":{  
      "taxClassificationId":null,
      "supplierScid":null,
      "gstNotRegisteredReason":null,      (boolean)
      "gstRegistered":null,               (boolean)
      "isIndiaGSTComposition":true        (boolean)
   },
   "createTime":"2017-07-17T06:48:52",    
}

新模式:

 {        
   "requestId":531956,
   "requestVersion":5,
   "supplier":{  
      "taxClassificationId":null,
      "supplierScid":null,
      "vatExemptionReason":null,         (boolean)
      "vatExemption":null,               (boolean)
      "AuxiliaryProperties":[
                   {
                    "id":"indiaGSTComposition",
                    "booleanValue":true
                    }
                  ]           
   },      
   "createTime":"2017-07-17T06:48:52",     
}

我想出了这个查询

update requests set data=regexp_replace(data::text, '"gstRegistered": ', '"vatExemption":', 'g')::jsonb;
update requests set data=regexp_replace(data::text, '"gstNotRegisteredReason": ', '"vatExemptionReason":', 'g')::jsonb;

但我不知道如何将isIndiaGSTComposition(boolean)转换为auxiliaryProperties(Array)。

请注意,如果isIndiaGSTComposition为null,则应为auxiliaryProperties:null。但如果它有真或假,则需要采用上述数据结构格式(如上面的“新模型”示例)。

感谢任何帮助。提前致谢 !

1 个答案:

答案 0 :(得分:0)

Postgres 9.4

db<>fiddle

在该版本中,您也可以使用regexp_replace函数:

UPDATE 
    requests
SET data =  
        regexp_replace(
            data::text,
            '"india"[\s]*:[\s]*(true|false|null)',                              -- A
            '"aux":' || CASE  
                            WHEN (data -> 'india')::text = 'null' THEN 'null'   -- B 
                            ELSE '[{"id":"india", "booleanValue":' || (data -> 'india')::text || '}]' -- C
                        END, 
            'g'
        )::jsonb;

A:查找整个india键/值对。使用[\s]*,可以在空白格式不同的情况下使用空格。

B / C:替换为字符串'"aux":something'。 “某物”是由CASE子句构建的:如果india具有字符串'null',则给出'null'(B)。否则,以原始数组india值(C)作为json数组字符串。

(我想知道为什么您需要一个aux值的数组...)


Postgres 9.6 +

db<>fiddle

此版本具有更好的json支持,因此无需文本强制转换和regexp子句即可解决问题-以更类似于json的方式进行发言。

https://www.postgresql.org/docs/9.6/static/functions-json.html

UPDATE 
    requests
SET 
    data = jsonb_insert(                                      -- A
               data - 'india',                                -- B
               '{aux}',                                       -- C
               CASE                                           -- D
                   WHEN data -> 'india' = 'null' THEN 'null'
                   ELSE jsonb_insert(                         -- E
                            '[{"id":"india"}]'::jsonb,        -- F
                            '{0, booleanValue}',              -- G
                            data -> 'india'                   -- H
                   ) 
               END
            );

A:jsonb_insert将新元素插入给定的json元素:

B:该函数的第一个参数是用于放置新对象的json。在这里,我使用数据对象,但之前删除了india元素。

C:第二个参数-插入新元素的路径:新的json对象将作为键"aux"的值插入。如果不存在(如本例所示),则会创建它。

D:第三个参数-要插入的元素:创建一个新元素。 CASE子句逻辑与上述版本相似。如果india的值为'null',请输入'null'。否则:

E:创建一个新的json元素并插入旧的india

F:新元素是静态json数组'[{"id":"india"}]'

G:这是一条路径:取第一个元素("0"),然后将新对象插入"booleanValue"。如果此密钥不存在,请创建它。

H:采用旧的india值。结果元素可以是[{"id":"india", "booelanValue: true"}]。这是(C)中"aux"元素的值