如何使用jpa根据postgres的jsonb列的条件(不使用本机查询)在Spring Boot中选择数据?

时间:2019-03-06 09:58:03

标签: spring postgresql spring-boot jpa jsonb

我有带jsonb字段的Postgres数据库。我在JPA中使用了条件构建器的条件列表的谓词列表。现在,我想基于多个原因和JSON来获取存储在数据库中的JSON数据。怎么可能呢?

Database table

private List<Predicate> whereClause(CriteriaBuilder criteriaBuilder, Root<KafkaLog> kafkaLog,
  KafkaLogSearchDto search) {
List<Predicate> predicates = new ArrayList<>();
if (search.getTopic() != null && !search.getTopic().isEmpty()) {
  Expression<String> literal =
      criteriaBuilder.literal("%" + search.getTopic().toUpperCase() + "%");
  predicates.add(criteriaBuilder.like(criteriaBuilder.upper(kafkaLog.get("topic")), literal));
}
if (search.getOffset() != null) {
  predicates.add(criteriaBuilder.equal(kafkaLog.get("offset"), search.getOffset()));
}
if (search.getResourceId() != null) {
  predicates.add(criteriaBuilder.equal(kafkaLog.get("invoiceId"), search.getResourceId()));
}
if (search.getPartition() != null) {
  predicates.add(criteriaBuilder.equal(kafkaLog.get("partition"), search.getPartition()));
}
if (search.getStatus() != null) {
  predicates.add(criteriaBuilder.equal(kafkaLog.get("status"), search.getStatus()));
}
if (search.getCreatedAtFrom() != null && search.getCreatedAtTo() != null) {
  predicates.add(criteriaBuilder.and(
      criteriaBuilder.greaterThanOrEqualTo(kafkaLog.get("createdAt").as(Date.class),
          search.getCreatedAtFrom()),
      criteriaBuilder.lessThanOrEqualTo(kafkaLog.get("createdAt").as(Date.class),
          search.getCreatedAtTo())));
}
if (search.getPayload() != null && !search.getPayload().isEmpty()) {
  Expression<String> literal =
      criteriaBuilder.literal("%" + search.getPayload().toUpperCase() + "%"); 



}
return predicates;

}

private CriteriaQuery<KafkaLog> getKafkaBySearchCriteria(KafkaLogSearchDto search, String orderBy,
  int sortingDirection) {
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<KafkaLog> criteriaQuery = criteriaBuilder.createQuery(KafkaLog.class);
Root<KafkaLog> kafkaLog = criteriaQuery.from(KafkaLog.class);

List<Predicate> predicates = whereClause(criteriaBuilder, kafkaLog, search);
criteriaQuery.where(predicates.toArray(new Predicate[] {}));

if (orderBy == null || orderBy.isEmpty()) {
  orderBy = "topic";
}
Expression<?> orderColumn = kafkaLog.get(orderBy);
if (orderColumn != null) {
  if (sortingDirection == 0) {
    criteriaQuery.orderBy(criteriaBuilder.asc(orderColumn));
  } else if (sortingDirection == 1) {
    criteriaQuery.orderBy(criteriaBuilder.desc(orderColumn));
  }
}
return criteriaQuery;

}

2 个答案:

答案 0 :(得分:0)

显然,自定义数据类型的支持一直到JDBC /数据库级别都不是JPA本身的一部分。只需阅读JSON,您就可以通过映射到String的实体来做到这一点(如果JPA实现允许的话)。

但是,您有一些选择:

  1. 如果您需要坚持使用JPA,则可以实现一个转换器来为您处理JSON(如本文所述为通用或更具体,您可以根据需要):Using JPA with PostgreSQL JSON
  2. 如果可以的话,放弃JPA并直接使用JDBC / SQL进行操作,这将给您PostgreSQL的全部潜能:how to store PostgreSQL jsonb using SpringBoot + JPA?

在读取JSONB字段时,您可以让数据库使用显式类型转换将其转换为String(因为JDBC中尚无直接JSON支持),例如:

SELECT payload::text FROM my_table WHERE ...

...或者对JSON字段本身进行一些精美的过滤,或者仅返回JSON数据的一部分。

答案 1 :(得分:0)

这是使用like子句搜索jsonb的示例谓词:

predicate.getExpressions()。add(cb.and(cb.like(cb.function(“ jsonb_extract_path_text”,String.class,root.get(“ tags”),cb.literal(this.key)),, “%” + this.value +“%”))));