更新 jsonb 列以替换特定元素

Update jsonb column to replace specific element

我想更新 jsonb 列以替换其中的数组元素,例如 Tv 到 TV。我在 table.

上使用 5M 行的 postgresql 12.4

前 10 行:

categories
["Air Conditioner", "Kitchen", "Bedding/Linens", "Parking", "Tv", "Child Friendly", "Internet", "Laundry"]
["Hot Tub", "Air Conditioner", "Kitchen", "Bedding/Linens", "Tv", "Wheelchair Accessible", "Pool", "Internet", "Laundry"]
["Hot Tub", "Air Conditioner", "Kitchen", "Bedding/Linens", "Balcony/Terrace", "Parking", "Tv", "Wheelchair Accessible", "Child Friendly", "Pool", "Internet", "Laundry"]
["Balcony/Terrace", "Kitchen", "Bedding/Linens", "Tv", "Wheelchair Accessible", "Internet", "Laundry"]
["Air Conditioner", "Kitchen", "Bedding/Linens", "Parking", "Tv", "Pool", "Internet", "Laundry"]
["Hot Tub", "Air Conditioner", "Kitchen", "Bedding/Linens", "Parking", "Balcony/Terrace", "Tv", "Child Friendly", "Internet", "Pet Friendly", "Laundry"]
["Hot Tub", "Air Conditioner", "Kitchen", "Bedding/Linens", "Balcony/Terrace", "Parking", "Tv", "Wheelchair Accessible", "Pool", "Internet", "Laundry"]
["Air Conditioner", "Kitchen", "Bedding/Linens", "Tv", "Wheelchair Accessible", "Internet", "Laundry"]
["Kitchen", "Bedding/Linens", "Parking", "Tv", "Internet", "Laundry"]
["Air Conditioner", "Kitchen", "Bedding/Linens", "Parking", "Tv", "Wheelchair Accessible", "Internet", "Laundry"]

什么是有效的:

UPDATE test_jsonb_update 
SET amenity_categories = replace(amenity_categories::TEXT,'"Tv"','"TV"')::jsonb 
WHERE id < 10;

我想要的:

我想知道在 jsonb 列上更新该元素的其他替代方法。我看过这个例子 并且我想在我的设备上使用类似 jsonb_set 的东西 案也。让我知道其他替代方案和最佳做法,因为我有 500 万条记录需要更新

恕我直言,你的方法是最有效的。以任何其他方式(如果你想保持顺序!)你需要将数组元素扩展到单独的行(要么检索旧"Tv"的索引以设置新的 "TV" 使用 jsonb_set 或字符串 search/replace) 到相同的位置并重新聚合所有...

demos:db<>fiddle

SELECT
    id,
    jsonb_agg(CASE WHEN elem = 'Tv' THEN 'TV' ELSE elem END) as new_array
FROM mytable,
    jsonb_array_elements_text(mydata) as elem
GROUP BY id

如果你真的想使用 jsonb_set(我相信这在这里没有意义)你可以这样做:

SELECT
    jsonb_set(mydata, ARRAY[s.elem_id]::text[], '"TV"') - 'Tv'
FROM mytable t
JOIN (
    SELECT
        id,
        elem_id
    FROM mytable,
        jsonb_array_elements_text(mydata) WITH ORDINALITY as elem(value, elem_id)
    WHERE elem.value = 'Tv'
)s ON s.id = t.id
  1. 扩展数组元素并显示它们的索引WITH ORDINALITY
  2. 现在您可以使用这些索引将新的 "TV" 元素放置到 jsonb_set()
  3. 的正确位置
  4. 之后您需要从更新的数组中删除旧的 "Tv" 元素。

最后更新:

UPDATE mytable t
SET mydata = s.my_array
FROM (
    -- query
) s
WHERE t.id = s.id

您的 json 数组的顺序似乎不固定,所以这应该可以完成工作并避免任何取消嵌套。

UPDATE ...
SET amenity_categories = (amenity_categories - 'Tv') || jsonb '["TV"]'
WHERE amenity_categories ? 'Tv';