如何以json格式从psql数据库返回嵌套数组

问题描述 投票:2回答:2

我将从顶部开始...我有两个表,引号和注释。一句话“有很多”的评论。我的最终目标是在前端有两个.map()函数,一个用于将所有引号呈现给我的页面,另一个用于呈现位于其上方的引用的每个注释。

我正在尝试从psql中检索一个返回如下内容的json:

[
{
"id": 1,
"content": "quote number 1!",
"name": null,
"num_of_flags": null,
"comments": [
  {
    "id": 1,
    "comment_content": "comment one!",
    "num_of_likes": null,
    "quote_id": 1
  },
  {
    "id": 1,
    "comment_content": "comment 2!",
    "num_of_likes": null,
    "quote_id": 1
  }
]

这样,'quotes'是一个对象数组,属于它的注释也是如此。

这是我实际上要回来的:

[
{
"id": 1,
"content": "quote number 1!",
"name": null,
"num_of_flags": null,
"comments": [
  {
    "id": 1,
    "comment_content": "comment 1!",
    "num_of_likes": null,
    "quote_id": 1
  }
]
},
{
"id": 2,
"content": "quote number 2!",
"name": null,
"num_of_flags": null,
"comments": [
  {
    "id": 2,
    "comment_content": "comment 2!",
    "num_of_likes": null,
    "quote_id": 2
  }
]
},
{
"id": 3,
"content": "quote number 3!",
"name": null,
"num_of_flags": null,
"comments": [
  {
    "id": 3,
    "comment_content": "comment 3",
    "num_of_likes": null,
    "quote_id": 1
  }
]
}
]

注意第三个'quote'对象。它包含'评论3'。注释3的quote_id为1,quote_id是一个外键,它应该仅与引号1相关,因此它不应该出现在引用对象3中。此外,我的数据库实际上包含所有这些的多个注释引号,但我的json只返回一个注释,它甚至没有正确引用。

这是我的架构:

BEGIN;

DROP TABLE IF EXISTS quotes;
DROP TABLE IF EXISTS comments;

CREATE TABLE quotes (
 id SERIAL PRIMARY KEY,
 name VARCHAR,
 content VARCHAR,
 num_of_flags INTEGER
);

CREATE TABLE comments (
 id SERIAL PRIMARY KEY,
 comment_content VARCHAR,
 num_of_likes INTEGER,
 quote_id INTEGER
);

ALTER TABLE ONLY comments
 ADD CONSTRAINT quotes_id_fkey
 FOREIGN KEY (quote_id)
 REFERENCES quotes(id);

COMMIT;

我查看了这个blog,并学习了一些关于json_agg聚合函数的知识,并且能够拼凑出一个确实将我的'comments'转换成数组的psql调用(正如你在本文的第二个代码块中看到的那样)。这是psql调用:

SELECT
      q.id,
      q.content,
      q.name,
      q.num_of_flags,
      json_agg(c.*) as comments
      FROM quotes q
      INNER JOIN comments c USING (id)
      GROUP BY q.id, q.content, q.name, q.num_of_flags

我认为关键是只调整psql调用,但我似乎无法做出正确的调整。我也尝试应用横向连接,以及我在this Stack Overflow帖子中找到的array_to_json方法,但是我的项目可能因为我的语法而无法应用它们。

希望这篇文章清晰易懂!我非常感谢你的时间,如果碰巧碰到它并能帮助我。

-法案

json postgresql multidimensional-array
2个回答
1
投票

注释错误引用的问题是因为你链接USING (id)上的表;相反,你应该使用ON quote.id = comment.quote_id。这可能也导致每个引用只显示一条评论,即使可能有多个或没有。

将行转换为JSON对象的最佳方法是使用json_build_object()(PG9.4 +)。 json_agg()将多个JSON对象组装成JSON数组。放在一起,你得到这个:

SELECT json_agg(quote_comments) AS json_object
FROM (
    SELECT json_build_object('id', q.id,
                             'name', q.name,
                             'content', q.content,
                             'num_of_flags', q.num_of_flags,
                             'comments', json_agg(c.j)) AS quote_comments
    FROM quotes q
    LEFT JOIN (
        SELECT quote_id, json_build_object('id', id,
                                           'comment_content', comment_content,
                                           'num_of_likes', num_of_likes,
                                           'quote_id', quote_id) AS j
        FROM comments) c ON c.quote_id = q.id
    GROUP BY 1, 2, 3, 4) sub;

JSON对其对象使用层次结构,您的查询应使用相同的层次结构构建;你可以使用子查询来做到这一点。在每个级别,您都构建一个JSON对象,并根据需要聚合到JSON数组中。由于您有两个级别的聚合,因此您无需在单个(子)查询中对不同的组进行分组,因此需要额外级别的子查询。


0
投票

Postgres 9.3版对JSON数据类型有很好的支持。你可以试试这个:

select q.*,  row_to_json(c.*) as comments from quotes q inner join comments c using(quote_id);

编辑后使用左连接:选择q。,row_to_json(c。)作为引号的注释q left join comments c ON q.id = c.quote_id;

© www.soinside.com 2019 - 2024. All rights reserved.