当前位置: 首页 > 知识库问答 >
问题:

如何使用复杂的Jsonb Postgresql列创建JPA谓词?

阴礼骞
2023-03-14

基本上,我有一个规范,以便过滤一个查询。在它的内部,需要添加一个新的谓词。

想象一个带有jsonb列(bar)的表(Z)。该列具有以下结构:

{
  "foo": {
    "A": {...},
    "B": {...},
    "C": "..."
  }
}
select *
from Z
where jsonb_exists_any(
   (select to_jsonb(
      array_to_json(src1.field_1)
   )
   from (
      select array_agg(src.field_1) as field_1
      from (select jsonb_object_keys(
         to_jsonb(jsonb_extract_path(
            Z.bar,
            'foo'))
         ) as field_1) src
      ) src1
   ),
array ['A','B']);
select jsonb_object_keys(
   to_jsonb(jsonb_extract_path(
      Z.bar,
      'foo')
   )
)

通过这样做:

criteriaBuilder.function(
   "jsonb_object_keys",
   Object.class,
   criteriaBuilder.function(
      "to_jsonb",
      Object.class,
      criteriaBuilder.function( "jsonb_extract_path",
         Object.class,
         root.get( "bar" ),
         criteriaBuilder.literal( "foo" ) )
   ) 
)

有什么建议吗?

共有1个答案

颜森
2023-03-14

你的例子很不幸我不太理解。以我的浅见,查询可以而且应该被简化。尽管如此,还是有一种方法可以将jsonb_extract_path(和其他jsonb函数)获取到一个JPA谓词中(使用hibernate作为实现)。

假设您想从z表中检索bar.foo所在的记录。

它的sql如下所示:

选择*from z,其中jsonb_extract_path(bar,'foo')不为空;

要将此查询转换为JPA谓词,您需要编写一个自己的谓词,该谓词扩展

org.hibernate.query.criteria.internal.predicate.AbstractSimplePredicate

和工具

org.hibernate.query.criteria.internal.expression.BinaryOperatorExpression

import org.hibernate.query.criteria.internal.CriteriaBuilderImpl;
import org.hibernate.query.criteria.internal.ParameterRegistry;
import org.hibernate.query.criteria.internal.Renderable;
import org.hibernate.query.criteria.internal.compile.RenderingContext;
import org.hibernate.query.criteria.internal.expression.BinaryOperatorExpression;
import org.hibernate.query.criteria.internal.expression.LiteralExpression;
import org.hibernate.query.criteria.internal.predicate.AbstractSimplePredicate;

import javax.persistence.criteria.Expression;
import java.io.Serializable;

import static java.lang.String.format;


public class ExtractJsonPath extends AbstractSimplePredicate implements
    BinaryOperatorExpression<Boolean>, Serializable {

   private final Expression<?> leftHandSide;

   private final Expression<?> rightHandSide;

   public ExtractJsonPath(CriteriaBuilderImpl criteriaBuilder, Expression<?> leftHandSide, Expression<?> rightHandSide) {
       super(criteriaBuilder);
       this.leftHandSide = leftHandSide;
       this.rightHandSide = rightHandSide;
   }


   @Override
   public Expression getLeftHandOperand() {
      return leftHandSide;
   }

   @Override
   public Expression getRightHandOperand() {
       return rightHandSide;
   }

   @Override
   public void registerParameters(ParameterRegistry registry) {
       Helper.possibleParameter(getLeftHandOperand(), registry);
       Helper.possibleParameter(getRightHandOperand(), registry);
   }

   @Override
   public String render(boolean isNegated, RenderingContext renderingContext) {
       return format(
            " jsonb_extract_path(%s, %s) ",
            ((Renderable) getLeftHandOperand()).render(renderingContext),
            ((Renderable) getRightHandOperand()).render(renderingContext)
       );
    }
}

在代码的某个地方,您需要在查询中放置WHERE子句:

  query.where(builder.isNotNull(
            new ExtractJsonPath(
                    (CriteriaBuilderImpl) builder,
                    root.get("bar"),
                    builder.literal("foo")
            ));
           new ExtractJsonPath(
                    (CriteriaBuilderImpl) builder,
                    new ExtractJsonPath(
                             (CriteriaBuilderImpl) builder,
                             root.get("bar"),
                             builder.literal("foo")
                    ),
                    builder.literal("x")
           ));

在这一点上,我想为没有完全采纳你的榜样而道歉。我希望这是一个可以接受的建议(或者至少是一个下降的开始),并祝你取得很多成功。

 类似资料:
  • 我试图利用Querydsl从表中获取一些结果。到目前为止,这是我尝试过的-- 如何在上面的中合并以便只获取第一个结果?

  • 如何使用在中创建复杂查询请求?我担心实体之间的关系。它们可能会影响请求的准备。 需要查询SQL,我的版本@Query:

  • 我需要使用stream().reduce()基于谓词创建2个列表。我有一个类似的代码,但它不起作用。

  • 我想创建一个自定义的nifi处理器,这样我就可以读取s7 plc数据。为此,我想将这个项目的java代码:https://github.com/s7connector/s7connector转换为一个nifi处理器。 因此,我已经下载了mvn包类型,就像webiste告诉的那样:https://medium.com/hashmapinc/creating-custom-processors-and

  • 我正在使用Spring靴2 /飞行路线/后退设置。 我想让Flyway创建一个表,其中包含自动键迭代的序列。JPA应该识别序列并使用它。 我让Flyway执行PostgreSQL脚本: 这是实体定义: 启动时抛出以下错误: 我的解释是Flyway成功执行了脚本并创建了一个序列。但是JPA想在之后创建序列并失败,因为它已经存在。如果我错了,请纠正我。 现在,如果可能的话,我如何配置JPA以重用现有序

  • 我是Criteria API的新手,我正在尝试创建一个对< code>B类型的实体进行计数的查询,其中< code > a . some method(B)= = true 。 我的实体: 我不知道使用JPA是否可以做到这一点,但我已经勾勒出了这个: 问题是我不知道如何创建与 一起使用的表达式。我的意思是,我甚至不知道我是否应该使用 来解决这个问题。 那么,有人能帮我吗?目前,我正在从数据库获取类