PostgreSQL 9.4:在数组内的 JSON 字段 id 上聚合/连接表
Posted
技术标签:
【中文标题】PostgreSQL 9.4:在数组内的 JSON 字段 id 上聚合/连接表【英文标题】:PostgreSQL 9.4: Aggregate / Join table on JSON field id inside array 【发布时间】:2014-10-23 02:01:45 【问题描述】:假设您有以下表格,比如说
表格:content_type
id 序列不为空 标签 json表格:data_type
id 序列号不为空 html 文本这只是一个小例子来说明。
存储在选项卡中的 json 可能像这样:
[
"name": "tab1",
"properties":
[
"name": "prop1",
"order": 1,
"help_text": "help text",
"description": "description",
"data_type": 1
]
,
"name": "tab2",
"properties":[
"name": "prop2",
"order": 1,
"help_text": "help text2",
"description": "description2",
"data_type": 1
,
"name": "prop3",
"order": 2,
"help_text": "help text3",
"description": "description3",
"data_type": 1
]
]
我现在想要实现的是像下面的伪代码一样进行连接:
SELECT content_type.id, content_type.tabs, data_type.id, data_type.html
FROM content_type
JOIN data_type
ON data_type.id = content_type.tabs::json->'data_type'::int
其中 data_type.id 和 data_type.html 实际上是连接到选项卡的属性的 data_type 而不是像上面通常的连接查询中那样作为单独的列。
基本上,我正在寻找的结果与将 2 个或多个表在列 id 上连接在一起时的结果相同,但在这种情况下,其中一个“表”位于 json 对象数组中。
是的,我知道上面的加入尝试非常遥远,因为我想将附加属性“添加/附加”到选项卡 json 列的修改版本,而不是作为附加的单独列。
在这种情况下,连接将返回 - 在 select/join 查询中 - tabs json 数组中的 id 并使用连接获取的附加属性对其进行扩展,因此它不会简单地返回“data_type”:1 它会返回一些东西喜欢:
"data_type":
"id":1,
"html": "<input type='text' id='%v' class='%v' placeholder='%v' value='%v' ng-model='%v'>"
...当然还有其他属性。这只是一个简单的例子来说明问题。
[
"name": "tab1",
"properties":
[
"name": "prop1",
"order": 1,
"help_text": "help text",
"description": "description",
"data_type":
"id":1,
"html": "<input type='text' id='%v' class='%v' placeholder='%v' value='%v' ng-model='%v'>"
... and of course additional columns fetched from the data_type table, and added to the select return in our join, to manipulate the original json array of tabs->properties->data_type
]
,
"name": "tab2",
"properties":[
"name": "prop2",
"order": 1... etc
希望这是有道理的,希望你能帮我解决这个问题,因为我似乎有点卡住了。
附言。 顺便说一句,使用最新的 9.4beta3。
我在这里找到了一个链接,让我希望这确实可以通过 PostgreSQL 实现:http://www.slideshare.net/EnterpriseDB/no-37327319(参见幻灯片 17)
其他可能有用的链接:
http://michael.otacoo.com/postgresql-2/manipulating-jsonb-data-with-key-unique/ http://hashrocket.com/blog/posts/faster-json-generation-with-postgresql PostgreSQL 9.2 row_to_json() with nested joins http://info.enterprisedb.com/rs/enterprisedb/images/EDB_White_Paper_Using_the_NoSQL_Features_in_Postgres.pdf (第 13 页)我尝试了一些实验 - 这是我目前所做的:
SELECT content_type.id, content_type.tabs as original, gf.json_agg as new_tabs
FROM content_type,
LATERAL (
select json_agg(row1) from((
select y.name, ss.extended_properties
from json_to_recordset(
(
select *
from json_to_recordset(
(
SELECT json_agg(ggg)
from(
SELECT tabs
FROM
(
SELECT
*
FROM content_type as ct
WHERE ct.id=content_type.id
) dsfds
)ggg
)
) as x(tabs json)
)
) as y(name text, properties json),
LATERAL (
select json_agg(row) as extended_properties
from(
select name, "order", data_type, data_type.html as data_type_html, help_text, description
from json_to_recordset(properties)
as k(name text, "order" int, data_type int, help_text text, description text)
JOIN data_type
ON data_type.id = k.data_type
)row
) ss
))row1
) gf
结果如下(在浏览器中放大以阅读图像中的文本 - 按住 ctrl + mwheel up og plus 键):
至少现在我可以把 data_type.html 放在那里,虽然我更喜欢 "data_type": "id": 1, "html": "[somehtmlhere]"
由于某种原因,它不允许我将 json_agg 包裹起来并将输出显示为 1 个组合的 json 文档。不明白为什么,但猜测它与 LATERAL 有关,它可能是 PostgreSQL 9.4 beta3 中的一个错误
我知道必须有更好的方法和解决方案来解决这个问题 - 我对 pgSQL 或一般 pg 不是很有经验......但是。
【问题讨论】:
我想这实现起来太复杂了,与在保存更改时简单地在 data_type 触发上创建触发器相比。然后,此触发器将查看所有 content_types 中的所有选项卡并在那里更新嵌入的 data_type。我想通过创建这个线程来尝试和避免,是避免这个嵌入式模型,并通过执行相当于在列 id 上加入表来简单地从嵌入式 id 中获取其余的 data_type 字段。 【参考方案1】:基本思想是您的查询应该期望您的 json 以某种方式构造,否则它会变得非常复杂。
基于预期的结构,我们可以使用json_to_recordset
将json 结构分解为列,并使用json_build_object
和json_agg
使用附加信息重建它。
WITH tab_properties_with_expanded_data_type AS (
SELECT
content_type.id AS content_type_id,
tab.name AS tab_name,
json_agg(
-- re-build the property object, but with additional data_type information
json_build_object(
'name', property.name,
'order', property.order,
'help_text', property.help_text,
'description', property.description,
'data_type', json_build_object('id', data_type.id, 'html', data_type.html)
)
) AS tab_properties
FROM content_type,
json_to_recordset(content_type.tabs) AS tab(name TEXT, properties JSON),
json_to_recordset(tab.properties) AS property(name TEXT, "order" INTEGER, help_text TEXT, description TEXT, data_type INTEGER)
LEFT JOIN data_type ON data_type.id = property.data_type
GROUP BY
content_type.id,
tab.name
)
SELECT
tab_properties_with_expanded_data_type.content_type_id AS id,
json_agg(
-- rebuild the tab object
json_build_object(
'name', tab_properties_with_expanded_data_type.tab_name,
'properties', tab_properties_with_expanded_data_type.tab_properties
)
)
FROM tab_properties_with_expanded_data_type
GROUP BY
tab_properties_with_expanded_data_type.content_type_id
这可行,但灵活性非常有限:我必须明确列出选项卡和属性的每个字段,并且我希望文档具有特定的结构。但这是一个好的开始:)
【讨论】:
以上是关于PostgreSQL 9.4:在数组内的 JSON 字段 id 上聚合/连接表的主要内容,如果未能解决你的问题,请参考以下文章
具有 postgresql 9.4 和 JSON 字段支持的 Peewee 连接池
将新的键/值对添加到 PostgreSQL JSON 列内的嵌套数组中