更新JSONB列,其中JSONB列具有特定值postgreSQL

时间:2019-11-02 13:45:43

标签: postgresql jsonb

我在Postgres数据库中有一个名为guest_group的表,以及一个名为custom_fields的列,其值如下:(示例)

[
   {
      "value":"Frau Barbara Test",
      "display_name":"Name",
      "servicio_tags":[
         "full-name"
      ]
   },
   {
      "value":"118",
      "display_name":"Zimmernummer",
      "servicio_tags":[
         "room-number"
      ]
   },
   {
      "value":"likes postgreSQL",
      "display_name":"Traces",
      "servicio_tags":[
         "trace"
      ]
   }
]

我想用

更新所有行
  • value等于Frau Barbara Test,其中servicio_tags数组等于["full-name"]
  • 加上value等于118,其中servicio_tags数组等于["room-number"]

更新应将新对象添加到JSONB:

{
   "value":"likes JSONB",
   "display_name":"Traces",
   "servicio_tags":[
      "trace"
   ]
}

到目前为止,我的尝试:

UPDATE guest_group 
SET custom_fields = 
jsonb_insert('[{"value": "Frau Barbara Test", "display_name": "Name", "servicio_tags": ["full-name"]}, {"value": "118", "display_name": "Zimmernummer", "servicio_tags": ["room-number"]}]'::jsonb,
'{0}', 
'{"value": "likes JSONB", "display_name": "Traces", "servicio_tags": ["trace"]}'::jsonb, 
true)
 where custom_fields::text like '%"Frau Barbara Test"%'
 and custom_fields::text like '%"118 "%'

此尝试将特定行的列中的值更改为以下内容:

[  
   {  
      "value":"Frau Barbara Test",
      "display_name":"Name",
      "servicio_tags":[  
         "full-name"
      ]
   },
   {  
      "value":"likes JSONB",
      "display_name":"Traces",
      "servicio_tags":[  
         "trace"
      ]
   },
   {  
      "value":"118",
      "display_name":"Zimmernummer",
      "servicio_tags":[  
         "room-number"
      ]
   }
]

所以:

   {
      "value":"likes postgreSQL",
      "display_name":"Traces",
      "servicio_tags":[
         "trace"
      ]
   }

迷路了。如何在不丢失此数据的情况下进行更新?

2 个答案:

答案 0 :(得分:1)

我建议不要将JSON比较为字符串。而是使用vast array of JSON operators and functions。要查找包含某个值的Test夫人的行,例如,可以使用@>运算符:

WHERE '[{"value": "Frau Barbara Test"}]'::jsonb <@ custom_fields

另请参阅Postgresql query array of objects in JSONB field

但是,这尚未检查是否具有full-name标签的同一对象,因此我们可以尝试

WHERE '[{"value": "Frau Barbara Test", "servicio_tags": ["full-name"]}]'::jsonb <@ custom_fields

这比文本比较要好得多,但仍然不完全符合您的要求。由于@>运算符的语义,它会检查标签数组以包含一个"full-name"字符串,而不是将其作为单个元素。

要做到这一点,它变得更加复杂,涉及到jsonb_array_elements上的子查询并显式访问其json组件以进行比较:

SELECT *
FROM guest_group
WHERE EXISTS(
  SELECT 1
  FROM jsonb_array_elements(custom_fields) AS el
  WHERE el->>'value' = 'Frau Barbara Test'
    AND el->'servicio_tags' = '["full-name"]'::jsonb)

您还可以使用ANY混合两种方法:

SELECT *
FROM guest_group
WHERE '{"value": "Frau Barbara Test"}' <@ ANY(
  SELECT el
  FROM jsonb_array_elements(custom_fields) AS el
  WHERE el->'servicio_tags' = '["full-name"]'::jsonb)

online demo

现在配备了这些工具,您可以添加第二个条件以匹配房间号。然后使用

UPDATE guest_group 
SET custom_fields = jsonb_insert(custom_fields, '{0}', '{"value": "likes JSONB", "display_name": "Traces", "servicio_tags": ["trace"]}'::jsonb, true)
WHERE …

答案 1 :(得分:0)

这似乎可行:

UPDATE guest_group 
SET custom_fields = 
jsonb_insert(custom_fields::jsonb,'{0}','{"value": "likes JSONB", "display_name": "Traces", "servicio_tags": ["trace"]}'::jsonb) 
WHERE custom_fields::text like '%"Frau Barbara Test"%'
AND custom_fields::text like '%"117"%'