【问题标题】:JSONB Data Type Modification in PostgresqlPostgresql 中的 JSONB 数据类型修改
【发布时间】:2022-01-24 08:07:05
【问题描述】:

我对在 postgres 中修改 jsonb 数据类型有疑问

基本设置:-

数组=> ["1", "2", "3"]
现在我有一个带有 id 列和一个名为 jsonb 数据类型 列的 postgresql 数据库让我们说cards

  id    cards
-----+---------
1       {"1": 3, "4": 2}

这就是名为test的表中的数据

问题:

如何将id->1的卡片从{"1": 3, "4": 2}转换成{"1": 4, "4":2, "2": 1, "3": 1}

我希望这些变化如何发生:

array 开始,将cards jsonb 中存在的所有数组元素加1 作为键,从而将{"1": 3} 更改为{"1": 4} 并插入符合以下条件的值不作为 cards jsonb 中的键存在,其值为 1 从而将 {"1":4, "4":2} 更改为 {"1":4, "4":2, "2 ":1, "3":1} 纯粹通过 postgres。

部分解决方案

我就我的问题向一位资深人士寻求支持,我被告知:-

大致(名称可能不同):对象键分解卡片,array_elements 分解数组,左连接它们,进行计算,重新聚合对象。可能有更直接的方法可以做到这一点,但上述蛮力方法会起作用。

  • 所以我尝试使用这两个函数json_each_text()json_array_elements_text() 来完成它,但最终陷入了中途,并且我无法理解左连接两列是什么意思:-
SELECT jsonb_each_text(tester_cards) AS each_text, jsonb_array_elements_text('[["1", 1], ["2", 1], ["3", 1]]') AS array_elements FROM tester WHERE id=1;

TLDR;

  • 更新语句,用于检查 jsonb 数据中数组中的一系列键是否存在,并自动递增 1 或将键分别插入值为 1 的 jsonb 中

现在看起来我要求被喂食,但我真的没有设法解决它,所以任何帮助将不胜感激????

【问题讨论】:

  • 你的前辈说得对。他们打算以SELECT * FROM jsonb_each_text(SELECT tester_cards FROM tester WHERE id=1) AS each_text, jsonb_array_elements_text('[["1", 1], ["2", 1], ["3", 1]]') AS array_elements; 开头。现在有两件事你可以LEFT JOIN
  • 或者,由于这是一个更新语句,您可能希望以这种方式从子查询开始:SELECT tester.id, (SELECT * FROM jsonb_each_text(tester.tester_cards) AS each_text, jsonb_array_elements_text('[["1", 1], ["2", 1], ["3", 1]]') AS array_elements) AS result FROM tester;
  • 你有数组["1", "2", "3"]还是数组[["1", 1], ["2", 1], ["3", 1]]
  • @Bergi 数组不是问题,因为它只是从我这边输入,所以可能是:D
  • 很抱歉,我仍然不明白 LEFT JOIN 将如何工作,因为我已经设法弄清楚了上一部分,但是我应该如何继续前进以进行更新声明

标签: postgresql jsonb


【解决方案1】:

关键的见解是,使用 jsonb_eachjsonb_object_agg,您可以在子查询中往返 JSON 对象:

SELECT id, (
  SELECT jsonb_object_agg(key, value)
  FROM jsonb_each(cards)
) AS result
FROM test;

(online demo)

现在您可以JOIN 这些键值对与数组输入的jsonb_array_elements 相对应。您的同事很接近,但并不完全正确:它需要完全外连接,而不仅仅是左(或右)连接来获取输出所需的所有对象键,除非您的一个输入是另一个输入的子集。

SELECT id, (
  SELECT jsonb_object_agg(COALESCE(obj_key, arr_value), …)
  FROM jsonb_array_elements_text('["1", "2", "3"]') AS arr(arr_value)
  FULL OUTER JOIN jsonb_each(cards) AS obj(obj_key, obj_value) ON obj_key = arr_value
) AS result
FROM test;

(online demo)

现在剩下的只是实际计算和转换为UPDATE 语句:

UPDATE test
SET cards = (
  SELECT jsonb_object_agg(
    COALESCE(key, arr_value),
    COALESCE(obj_value::int, 0) + (arr_value IS NOT NULL)::int
  )
  FROM jsonb_array_elements_text('["1", "2", "3"]') AS arr(arr_value)
  FULL OUTER JOIN jsonb_each_text(cards) AS obj(key, obj_value) ON key = arr_value
);

(online demo)

【讨论】:

  • 这很有见地,我将妥善整理所有信息。谢谢你的详细解释。
  • 怎么可能有不同的增量值我认为简单地将更多相同的值放入数组中会产生这种效果,例如 FROM jsonb_array_elements_text('["1", "2", " 2", "5", "5", "5"]') 作为 arr(arr_value) 它没有任何效果,但是相同的 +1 增量只有一次。
  • 我猜你需要某种GROUP BYcount(…)jsonb_object_agg 只是忽略重复键并保留最后一个值。你可以看到here 非聚合元组的样子。但是,我建议您不要复制数组中的键值,而是将 {"1": 1, "2": 2, "5": 3} 作为对象传递
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-15
  • 1970-01-01
  • 2022-01-17
相关资源
最近更新 更多