json - 获取自下而上的嵌套json以在postgresql中进行查询

标签 json postgresql

给定下表,我想通过 ID 查找类别,然后获取包含其父行的 JSON 对象作为 JSON。如果我查找类别 ID 999,我想要以下 json 结构。

我怎样才能做到这一点?

{
  id: 999
  name: "Sprinting",
  slug: "sprinting",
  description: "sprinting is fast running",
  parent: {
    id: 2
    name: "Running",
    slug: "running ",
    description: "All plans related to running.",
    parent: {
      id: 1
      name: "Sport",
      slug: "sport ",
      description: null,
    }
  }
}
CREATE TABLE public.categories (
    id integer NOT NULL,
    name text NOT NULL,
    description text,
    slug text NOT NULL,
    parent_id integer
);

INSERT INTO public.categories (id, name, description, slug, parent_id) VALUES (1, 'Sport', NULL, 'sport', NULL);
INSERT INTO public.categories (id, name, description, slug, parent_id) VALUES (2, 'Running', 'All plans related to running.', 'running', 1);
INSERT INTO public.categories (id, name, description, slug, parent_id) VALUES (999, 'Sprinting', 'sprinting is fast running', 'sprinting', 2);```

最佳答案

demo:db<>fiddle

(解释如下)

WITH RECURSIVE hierarchy AS (
    SELECT id, parent_id
    FROM categories 
    WHERE id = 999
    
    UNION
    
    SELECT
        c.id, c.parent_id
    FROM categories c
    JOIN hierarchy h ON h.parent_id = c.id
),
jsonbuilder AS (
    SELECT 
        c.id, 
        h.parent_id,
        jsonb_build_object('id', c.id, 'name', c.name, 'description', c.description, 'slug', c.slug) as jsondata
    FROM hierarchy h
    JOIN categories c ON c.id = h.id
    WHERE h.parent_id IS NULL
    
    UNION
    
    SELECT
        c.id,
        h.parent_id,
        jsonb_build_object('id', c.id, 'name', c.name, 'description', c.description, 'slug', c.slug, 'parent', j.jsondata)  
    FROM hierarchy h
    JOIN categories c ON c.id = h.id
    JOIN jsonbuilder j ON j.id = h.parent_id
)
SELECT 
    jsondata
FROM jsonbuilder
WHERE id = 999

通常您需要递归查询来创建嵌套的 JSON 对象。天真的方法是:

  1. 获取id = 999的记录,创建一个JSON对象
  2. 获取 id = parent_id 的记录 999 (id = 2),构建 JSON 对象,将此 als parent 属性添加到以前的对象。
  3. 重复第2步直到parent为NULL

不幸的是,我没有看到添加嵌套父级的简单方法。每一步都将 JSON 嵌套得很深。是的,我敢肯定,有一种方法可以做到这一点,存储 parent 的路径并每次使用 jsonb_set()。这可行。

另一方面,将当前创建的 JSON 对象放入一个新对象中要简单得多。可以说,方法是从最深层次构建JSON。为此,您还需要父路径。但是,您可以先使用单独的递归查询创建它,而不是在创建 JSON 对象时创建和存储它:

WITH RECURSIVE hierarchy AS (
    SELECT id, parent_id
    FROM categories 
    WHERE id = 999
    
    UNION
    
    SELECT
        c.id, c.parent_id
    FROM categories c
    JOIN hierarchy h ON h.parent_id = c.id
)
SELECT * FROM hierarchy

获取带有 id = 999 的记录及其父级。然后获取父记录,它的 id 和它的 parent_id。这样做直到 parent_idNULL

这会产生:

 id | parent_id
--: | --------:
999 |         2
  2 |         1
  1 |      null

现在我们有一个简单的映射列表,它显示了遍历树。与我们的原始数据有何不同?如果您的数据包含两个或更多 child ,记录为 id = 1,我们将不知道我们必须带哪个 child 才能最终到达 child 999。然而,这个结果只列出了祖先关系,不会返回任何 sibling 。

有了这个,我们就可以从最顶层的元素开始遍历树:

  1. 获取没有父项的记录。从其数据创建一个 JSON 对象。
  2. 获取上一条记录的子记录。从其数据创建一个 JSON 对象,并将之前的 JSON 数据作为父对象嵌入。
  3. 继续,直到没有 child 。

它是如何工作的?

此查询使用 recursive CTEs .第一部分是初始查询,可以说是第一条记录。第二部分,UNION 之后的部分,是递归部分,通常引用 WITH 子句本身。这始终是对上一回合的引用。

JSON 部分只是使用 jsonb_build_object() 创建一个 JSON 对象,它采用任意数量的值。因此,我们可以使用当前记录数据,此外还可以为 parent 属性使用上一轮已创建的 JSON 数据。

关于json - 获取自下而上的嵌套json以在postgresql中进行查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65338865/

相关文章:

mysql - 如果以前为 postgres 安装了 thinking sphinx,我是否需要为 mysql 重新安装它?

php - 从$ json打印youtube元数据

SQL 特定顺序

PostgreSQL - CREATE TABLE - 在复合类型内的属性中应用 PRIMARY KEY 等约束

javascript - PHP json_encode() - SQL 限制和 AJAX js

sql - Postgres 是否会在更新时重写整行?

sql - 通过 LoginRoles 与表在 Web 应用程序上进行 Postgres 用户身份验证

java - 如何通过 jackson 库比较两个 JSON 对象的结构(忽略值)?

asp.net-mvc - ASP.NET MVC Web API : Posting a list of objects

php - 每当mysql更新时动态更新json文件