PostgreSQL 9.4:数组内JSON字段id的聚合/连接表

时间:2014-10-23 02:01:45

标签: json postgresql join field

假设您有以下表格,比如说

table:content_type

  • id serial not null
  • tabs json

table:data_type

  • id serial not null
  • html text

这只是一个很好的例子来说明。

存储在选项卡中的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而不是像上面通常的连接查询中那样的单独列。

基本上我正在寻找与在列id上连接在一起的2个或更多个表时相同的结果,除了在这种情况下其中一个“表”位于json对象的数组中。 / p>

是的,我知道上面的连接尝试距离很远,因为我想将附加属性“添加/附加”到选项卡json列的修改版本,而不是作为附加的单独列。

在这种情况下,连接将返回 - 在select / join查询中 - 选项卡json数组中的id,并使用join-fetched其他属性扩展它,因此不是简单的“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 btw。

我在这里找到了一个链接,希望通过PostgreSQL确实可以实现这一点:http://www.slideshare.net/EnterpriseDB/no-37327319参见幻灯片17

其他可能有用的链接:


我尝试了一下 - 这是我到目前为止所做的:

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键):

enter image description here

至少现在我可以放入data_type.html,虽然我更喜欢“data_type”:{“id”:1,“html”:“[somehtmlhere]”}

由于某种原因,它不允许我在它周围包装json_agg并将输出显示为1个组合的json文档。不要忘了为什么,但猜测它与LATERAL有关,它可能是PostgreSQL 9.4 beta3中的一个错误

我知道必须有一种更好的方法和解决方案 - 我对pgSQL或pg一般都没有经验......但是。

1 个答案:

答案 0 :(得分:2)

基本思想是你的查询应该期望你的json以某种方式结构化,否则它会变得非常复杂。 根据预期的结构,我们可以使用json_to_recordset将json结构剖析为列,并使用json_build_objectjson_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

这有效但在灵活性方面非常有限:我必须明确列出选项卡和属性的每个字段,并且我希望文档具有特定的结构。但这是一个好的开始:)