首页 > 解决方案 > Golang 结构的 Postgres 数组

问题描述

我有以下 Go 结构:

type Bar struct {
    Stuff string `db:"stuff"`
    Other string `db:"other"`
}

type Foo struct {
    ID    int    `db:"id"`
    Bars  []*Bar `db:"bars"`
}

所以Foo包含一片Bar指针。我在 Postgres 中也有以下表格:

CREATE TABLE foo (
    id  INT
)

CREATE TABLE bar (
    id      INT,
    stuff   VARCHAR,
    other   VARCHAR,
    trash   VARCHAR
)

我想LEFT JOIN放在桌子上bar并将其聚合为要存储在 struct 中的数组Foo。我试过了:

SELECT f.*,
ARRAY_AGG(b.stuff, b.other) AS bars
FROM foo f
LEFT JOIN bar b
ON f.id = b.id
WHERE f.id = $1
GROUP BY f.id

但看起来ARRAY_AGG函数签名不正确(function array_agg(character varying, character varying) does not exist)。有没有办法在不单独查询的情况下做到这一点bar

标签: postgresqlgosqlx

解决方案


看起来你想要的是bars一个 bar 对象数组来匹配你的 Go 类型。为此,您应该使用JSON_AGG而不是ARRAY_AGG因为ARRAY_AGG仅适用于单列,并且在这种情况下会生成文本类型 ( TEXT[]) 的数组。JSON_AGG,另一方面,创建一个 json 对象数组。您可以将其与JSON_BUILD_OBJECT仅选择所需的列相结合。

这是一个例子:

SELECT f.*,
JSON_AGG(JSON_BUILD_OBJECT('stuff', b.stuff, 'other', b.other)) AS bars
FROM foo f
LEFT JOIN bar b
ON f.id = b.id
WHERE f.id = $1
GROUP BY f.id

然后你必须处理在 Go 中解组 json,但除此之外你应该很高兴。

另请注意,在将 json 解组为结构时,Go 会为您忽略未使用的键,因此您可以根据bar需要选择表上的所有字段来简化查询。像这样:

SELECT f.*,
JSON_AGG(TO_JSON(b.*)) AS bars -- or JSON_AGG(b.*)
FROM foo f
LEFT JOIN bar b
ON f.id = b.id
WHERE f.id = $1
GROUP BY f.id

如果您还想处理 inbar中的记录没有条目的情况foo,您可以使用:

SELECT f.*,
COALESCE(
    JSON_AGG(TO_JSON(b.*)) FILTER (WHERE b.id IS NOT NULL),
    '[]'::JSON
) AS bars
FROM foo f
LEFT JOIN bar b
ON f.id = b.id
WHERE f.id = $1
GROUP BY f.id

如果没有FILTER,您将获得[NULL]infoo中没有相应行的行bar,而FILTER只是给您NULL,然后只需使用它COALESCE来转换为空的 json 数组。


推荐阅读