当前位置: 首页 > 面试题库 >

Postgres-将邻接表转换为嵌套的JSON对象

阎成天
2023-03-14
问题内容

我在Postgres中有一个包含此数据的表,并且很难将其转换为JSON对象。

node_id    parent_node    name
-------    -----------    ----
1                         node1
2          1              node2
3          1              node3
4          2              node4
5          2              node5
6          2              node6
7          3              node7
8          3              node8

我该如何转换呢?

{
    name: 'node1'
    childs: [
        { 
            name: 'node2',
            childs: [
                {
                    name: 'node4',
                    childs: []
                },
                {
                    name: 'node5',
                    childs: []
                },
                {
                    name: 'node6',
                    childs: []
                }
            ]
        },
        ...    
    ]
}

任何建议都会有所帮助。谢谢


问题答案:

使用WITH RECURSIVEhttps://www.postgresql.org/docs/current/static/queries-
with.html
)和JSON函数(https://www.postgresql.org/docs/current/static/functions-
json.html
)我建立这个解决方案:

db
<>小提琴

核心功能:

    WITH RECURSIVE tree(node_id, ancestor, child, path, json) AS  (
      SELECT 
          t1.node_id, 
          NULL::int, 
          t2.node_id,
          '{children}'::text[] || 
             (row_number() OVER (PARTITION BY t1.node_id ORDER BY t2.node_id) - 1)::text,-- C
          jsonb_build_object('name', t2.name, 'children', array_to_json(ARRAY[]::int[])) -- B
      FROM test t1
      LEFT JOIN test t2 ON t1.node_id = t2.parent_node                                   -- A
      WHERE t1.parent_node IS NULL

      UNION

      SELECT
          t1.node_id, 
          t1.parent_node, 
          t2.node_id,
          tree.path || '{children}' || (row_number() OVER (PARTITION BY t1.node_id ORDER BY t2.node_id) - 1)::text, 
          jsonb_build_object('name', t2.name, 'children', array_to_json(ARRAY[]::int[]))
      FROM test t1
      LEFT JOIN test t2 ON t1.node_id = t2.parent_node
      INNER JOIN tree ON (t1.node_id = tree.child)
      WHERE t1.parent_node = tree.node_id                                                -- D
    )
    SELECT                                                                               -- E
        child as node_id, path, json 
    FROM tree 
    WHERE child IS NOT NULL ORDER BY path

每个元素都WITH RECURSIVE包含一个开始SELECT部分和一个递归部分(第二个部分SELECT),并由组合UNION

答:再次参加餐桌本身就可以找到的孩子node_id

B:为孩子建立json对象,可以将其插入其父对象

C:构建必须在其中插入子对象的路径(从根目录开始)。窗口函数row_number()(https://www.postgresql.org/docs/current/static/tutorial-
window.html)生成父级子级数组中子级的索引。

D:递归部分作为初始部分起作用,但有一个区别:它不是在搜索根元素,而是在搜索具有上一个递归的父节点的元素。

E:执行递归并过滤所有元素而没有任何子元素将得到以下结果:

node_id   path                      json
2         children,0                {"name": "node2", "children": []}
4         children,0,children,0     {"name": "node4", "children": []}
5         children,0,children,1     {"name": "node5", "children": []}
6         children,0,children,2     {"name": "node6", "children": []}
3         children,1                {"name": "node3", "children": []}
7         children,1,children,0     {"name": "node7", "children": []}
8         children,1,children,1     {"name": "node8", "children": []}

尽管我找不到在递归中添加所有子元素的方法(origin
json不是全局变量;所以它始终知道直接祖先的更改,而不是其兄弟姐妹的更改),但我不得不在几秒钟的时间内迭代这些行。

这就是为什么我构建函数。在这里,我可以对全局变量进行迭代。使用该功能,jsonb_insert我将所有计算出的元素插入到根json对象中-
使用计算出的路径。

CREATE OR REPLACE FUNCTION json_tree() RETURNS jsonb AS $$
DECLARE
    _json_output jsonb;
    _temprow record;
BEGIN
    SELECT 
        jsonb_build_object('name', name, 'children', array_to_json(ARRAY[]::int[])) 
    INTO _json_output 
    FROM test 
    WHERE parent_node IS NULL;

    FOR _temprow IN
        /* Query above */
    LOOP
        SELECT jsonb_insert(_json_output, _temprow.path, _temprow.json) INTO _json_output;
    END LOOP;

    RETURN _json_output;
END;
$$ LANGUAGE plpgsql;

最后一步是调用函数,并使JSON更具可读性(jsonb_pretty()

{
    "name": "node1",
    "children": [{
        "name": "node2",
        "children": [{
            "name": "node4",
            "children": []
        },
        {
            "name": "node5",
            "children": []
        },
        {
            "name": "node6",
            "children": []
        }]
    },
    {
        "name": "node3",
        "children": [{
            "name": "node7",
            "children": []
        },
        {
            "name": "node8",
            "children": []
        }]
    }]
}

我敢肯定有可能优化查询,但是对于草图它是可行的。



 类似资料:
  • 问题内容: 有人可以提供一个示例或参考,该示例或参考提供一种使用Jackson库将嵌套JAVA对象转换为JSON输出的方法的方法。我没有转换平面JAVA对象的问题。但是,JSON库显示嵌套的对象名称和类型,而不是其子对象。我几乎可以利用此处提供的相同代码http://www.mkyong.com/java/jackson-2-convert- java-object-to-from-json/ 。

  • 问题内容: 我是Python和Pandas的新手。我正在尝试将Pandas Dataframe转换为嵌套的JSON。函数.to_json()不能为我的目标提供足够的灵活性。 以下是数据框的一些数据点(在csv中,以逗号分隔): 有很多重复的信息,我想要一个这样的JSON: 我怎样才能做到这一点? 编辑: 再现数据帧的代码: 问题答案: 更新: 结果(格式化): 旧答案: 你可以用它做的,和方法:

  • 我有一个嵌套的JSON对象,如下所示: 我想将其转换为: 我如何使用JOLT实现这一点?感谢您的参与。

  • 输入 json : 预期输出: 我想有一个颠簸转换,它可以嵌套很少的田地。

  • 我认为将对象强制转换为相当简单,但是

  • 问题内容: 我正在寻找一种优雅的方式来获取数据,该数据使用具有一些嵌套dict和列表(例如javascript样式对象语法)的dict进行属性访问。 例如: 应该以这种方式访问​​: 我认为,没有递归是不可能的,但是获得字典对象样式的一种好方法是什么? 问题答案: 更新:在Python 2.6及更高版本中,请考虑namedtuple数据结构是否满足你的需求: 备选方案(原始答案内容)为: 然后,你