使用 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()
的解决方案,但我认为这不是最佳做法,因为那样的话我们得到我们的字段 title
和 desc
就像通常通过 [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 ...))
不久前我开始使用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()
的解决方案,但我认为这不是最佳做法,因为那样的话我们得到我们的字段 title
和 desc
就像通常通过 [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 ...))