Golang 结构的 Postgres 数组

the*_*may 1 postgresql go sqlx

我有以下 Go 结构:

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

type Foo struct {
    ID    int    `db:"id"`
    Bars  []*Bar `db:"bars"`
}
Run Code Online (Sandbox Code Playgroud)

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

CREATE TABLE foo (
    id  INT
)

CREATE TABLE bar (
    id      INT,
    stuff   VARCHAR,
    other   VARCHAR,
    trash   VARCHAR
)
Run Code Online (Sandbox Code Playgroud)

我想LEFT JOIN在 table 上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
Run Code Online (Sandbox Code Playgroud)

但看起来ARRAY_AGG函数签名不正确(function array_agg(character varying, character varying) does not exist)。有没有办法在不进行单独查询的情况下执行此操作bar

Hen*_*ody 5

看起来您想要的是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
Run Code Online (Sandbox Code Playgroud)

然后你必须在 Go 中处理 json 的解组,但除此之外你应该可以开始了。

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

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
Run Code Online (Sandbox Code Playgroud)

如果您还想处理 中没有bar记录条目的情况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
Run Code Online (Sandbox Code Playgroud)

如果没有FILTER,您将获得 中 的[NULL]行,而foo中 没有对应的行bar,而FILTER则为您提供NULL,然后仅用于COALESCE转换为空的 json 数组。