PostgreSQL将JSONB对象更新为数组

问题描述

我不知道为什么,但是PHP可能会将我的某些数据作为对象持久保存,而将某些数据作为数组持久保存。我的桌子看起来像:

seller_info_address表:

 ID (INT)  |  address (JSONB)                                  |
------------+--------------------------------------------------|
     1      | {"addressLines":{"0":"Technology Park",...},...} |
     2      | {"addressLines":["Technology Park",...],...}     |

某些addressLines是对象:

{
  "addressLines": {
    "0": "Technology Park","1": "Blanchard Road","3": "dublin","4": "2"
  },"companyName": "...","emailAddress": [],"...": "..."
}

某些addressLines是数组:

{
  "addressLines": [
    "Technology Park","Blanchard Road","dublin","2"
  ],"...": "..."
}

我想用SQL查询来均衡数据,但是我不确定该怎么做。所有addressLines保留为对象的对象都应更新为数组形式。

感谢您的帮助,谢谢!

解决方法

您可以使用以下方法将对象转换为数组:

select id,(select jsonb_agg(e.val order by e.key::int) 
            from jsonb_each(sia.address -> 'addressLines') as e(key,val))
from seller_info_address sia
where jsonb_typeof(address -> 'addressLines') = 'object'

where条件确保我们仅对非数组的地址行执行此操作。

使用的聚合也可以在UPDATE语句中使用:

update seller_info_address
  set address = jsonb_set(address,'{addressLines}',(select jsonb_agg(e.val order by e.key::int) 
                           from jsonb_each(address -> 'addressLines') as e(key,val))
                          )
where jsonb_typeof(address -> 'addressLines') = 'object';
,

好的,我现在自己找到了解决方案。绝对不是最雄辩的解决方案。我敢肯定,有一个更好,更高效的解决方案,但是它可以工作...

DROP FUNCTION update_address_object_to_array(id INTEGER);
CREATE OR REPLACE FUNCTION
    update_address_object_to_array(id INTEGER)
    RETURNS VOID AS
$UPDATE_ADDRESS_OBJECT_TO_ARRAY$
BEGIN
    UPDATE seller_info_address
    SET address = jsonb_set(address,(
        SELECT CASE
                   WHEN jsonb_agg(addressLines) IS NOT NULL THEN jsonb_agg(addressLines)
                   ELSE '[]'
               END
        FROM seller_info_address sia,jsonb_each(address #> '{addressLines}') as t(key,addressLines)
        WHERE jsonb_typeof(sia.address -> 'addressLines') = 'object'
          AND seller_info_id = update_address_object_to_array.id
    ),true)
    WHERE seller_info_id = update_address_object_to_array.id
      AND jsonb_typeof(address -> 'addressLines') = 'object';
END
$UPDATE_ADDRESS_OBJECT_TO_ARRAY$
    LANGUAGE 'plpgsql';
SELECT update_address_object_to_array(sia.seller_info_id)
  FROM seller_info_address sia
 WHERE jsonb_typeof(address -> 'addressLines') = 'object';

内部SELECT使用addressLines获取jsonb_each对象中的所有行,然后使用jsonb_agg将它们聚合到一个数组中。条件表达式是为了防止出现空情况。

然后将结果通过jsonb_set存储到UPDATE中的json中所需的位置。在哪里应该不言自明。