使用 JOOQ 在查询构建器中函数 json 对象,json 数组

functions json object, json array in query builder using JOOQ

不久前我开始使用jooq。我喜欢它,但我在构建查询时遇到了问题。

我的工具是Postgresql,java 11、Springboot。我想从数据库中获取一些没有额外行的数据。

我有两个表,它们之间是多对多关系。 轻松使用 sql:

SELECT author_book.author_id, author.name, json_agg(json_build_object(
    'title', book.title,
    'desc', book.desc)) as info
FROM author_book
        JOIN book on book.id = author_book.book_id
        JOIN author on author.id = author_book.author_id
WHERE author_id = 1687
group by author_id, author.name;

然后我得到了这个:

id name info
id author [{ "title" : "title_1", "desc" : "desc_1"}, {"title" : "title_2", "desc" : "desc_2"}, ...]

事情是将字段 {book.title, book.desc} 组合在一个对象中并收集到一个数组中。然后在 java 中,我们可以轻松地将此类对象解析为内部模型。

我在 jooq 中试过这样的查询:

Integer myAuthorId;
defaultDSLContext.select(
                authorBookTable.AUTHOR_ID,
                authorTable.NAME,
                DSL.jsonArrayAgg(DSL.jsonbObject(
                        key("title").value(bookTable.TITLE),
                        key("desc").value(bookTable.DESC)))              
                        .as("info"))
                .from(authorBookTable)
                .join(bookTable).on(bookTable.ID.eq(authorBookTable.BOOK_ID))
                .join(authorTable).on(authorTable.ID.eq(authorBookTable.AUTHOR_ID))
                .where(authorBookTable.AUTHOR_ID.eq(myAuthorId))
                .groupBy(authorBookTable.AUTHOR_ID,
                        authorTable.NAME)
                .fetchOne()

我的导入:

import com.google.gson.Gson;
import org.jooq.impl.DSL;
import org.jooq.impl.DefaultDSLContext;
import org.springframework.stereotype.Repository;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static org.jooq.impl.DSL.key;

不幸的是我遇到了一个错误:

SQL [select "public"."author_book"."author_id", "public"."author"."name",
json_arrayagg(json_object(key ? value "public"."book"."title", key ? value "public"."book"."desc")) "info" 
from "public"."author_book" 
join "public"."book" on "public"."book"."id" = "public"."author_book"."book_id" 
join "public"."author" on "public"."author"."id" = "public"."author_book"."author_id" 
where "public"."author_book"."author_id" = ? 
group by "public"."author_book"."author_id", "public"."author"."name"]; 
ERROR: syntax error at or near ""
  Position: 104

如何使用 jsonObject() 的示例我在此处看到 json-object-function and here blog.jooq。我很乐意根据您的建议解决此问题。

那有什么办法解决呢?为什么不行呢?

实际上,我找到了使用 arrayAgg()array() 代替 jsonArrayAgg()jsonObject() 的解决方案,但我认为这不是最佳做法,因为那样的话我们得到我们的字段 titledesc 就像通常通过 [0], [1].

获取数组中的元素一样

如果使用 json 聚合的目标是将查询结果映射到对象的嵌入式列表,例如

public class SomeDto {
    // ...other fields
    private List<InnerDto> innerDtoList;
}

那你可以试试https://simpleflatmapper.org/

所以在你的例子中它看起来像那样

依赖关系:

implementation 'org.simpleflatmapper:sfm-jooq:{version}'
implementation 'org.simpleflatmapper:sfm-jdbc:{version}'
implementation 'org.simpleflatmapper:sfm-map:{version}'

dto:

public class AuthorDto {

    @Key
    private Integer authorId;
    @Key
    private String name;

    private List<InfoDto> infos;
}

public class InfoDto {

    private String title;
    private String desc;
}

jooq查询:

public List<AuthorDto> fetchAuthors(Integer myAuthorId) {

    final Select<?> query = defaultDSLContext
        .select(
            authorBookTable.AUTHOR_ID,
            authorTable.NAME,
            bookTable.TITLE.as("infos.title"), 
            bookTable.DESC.as("infos.desc")
        )
        .from(authorBookTable)
        .join(bookTable).on(bookTable.ID.eq(authorBookTable.BOOK_ID))
        .join(authorTable).on(authorTable.ID.eq(authorBookTable.AUTHOR_ID))
        .where(authorBookTable.AUTHOR_ID.eq(myAuthorId));

        try (final ResultSet resultSet = query.fetchResultSet()) {
            
            return JdbcMapperFactory
                .newInstance()
                .newMapper(AuthorDto.class)
                .stream(resultSet)
                .collect(toList());

         } catch (final SQLException e) {
             // ...
         }

}

或者,您可以在 base class 或 utils class 的某处编写泛型方法,而不是到处都这样做。像这样:

protected <T> List<T> groupingFetch(final Select<?> query, final Class<? extends T> type) {

    try (final ResultSet resultSet = query.fetchResultSet()) {

        return JdbcMapperFactory
            .newInstance()
            .newMapper(type)
            .stream(resultSet)
            .collect(toList());
    
    } catch (final SQLException e) {
        // ...
    }
}

您似乎没有正确配置 jOOQ 在 defaultDSLContext 实例中使用 SQLDialect.POSTGRES,否则它不会生成标准的 SQL/JSON 语法,例如:

json_arrayagg(json_object(key ? value ...))