如何使用spring数据jpa查询jsonb列?

Jos*_* C. 4 postgresql spring jpa spring-data-jpa

我在使用postgres 9.4实例获取此本机查询时遇到问题.

我的存储库有一个方法:

 @Query(value = "SELECT t.* " +
            "FROM my_table t " +
            "WHERE t.field_1 = ?1 " +
            "AND t.field_2 = 1 " +
            "AND t.field_3 IN ?2 " +
            "AND t.jsonb_field #>> '{key,subkey}' = ?3",
            nativeQuery = true)
    List<Entity> getEntities(String field1Value,
                                   Collection<Integer> field3Values,
                                   String jsonbFieldValue);
Run Code Online (Sandbox Code Playgroud)

但是日志显示了这个:

SELECT t.* FROM my_table t 
WHERE t.field_1 = ?1 
  AND t.field_2 = 1 
  AND t.field_3 IN ?2 
  AND t.jsonb_field ? '{key,subkey}' = ?3
Run Code Online (Sandbox Code Playgroud)

我得到这个例外:

内部异常:org.postgresql.util.PSQLException:没有为参数2指定值.

我在方法调用之前直接记录了参数,并且它们都是提供的.

我不确定为什么在日志中#>>显示?.我需要逃脱#>>吗?我需要格式化集合IN吗?我需要逃离json路径吗?

当我直接对db执行查询时,它可以工作.例:

SELECT *
FROM my_table t
WHERE t.field_1 = 'xxxx'
  AND t.field_2 = 1
  AND t.field_3 IN (13)
  AND t.jsonb_field #>> '{key,subkey}' = 'value'
Run Code Online (Sandbox Code Playgroud)

Geo*_*lou 12

我发现弹簧数据中的规范 api 非常有用.
假设我们有一个名称实体和名称类型为JSON(B)Product的属性title.
我假设此属性包含不同语言的产品标题.一个例子可能是:{"EN":"Multicolor LED light", "EL":"????????? LED ???"}.
下面的源代码通过标题和作为参数传递的语言环境找到(或者更多,如果它不是唯一字段)产品.

@Repository
public interface ProductRepository extends JpaRepository<Product, Integer>, JpaSpecificationExecutor<Product> {
}


public class ProductSpecification implements Specification<Product> {

    private String locale;
    private String titleToSearch;

    public ProductSpecification(String locale, String titleToSearch) {
        this.locale = locale;
        this.titleToSearch = titleToSearch;
    }

    @Override
    public Predicate toPredicate(Root<Product> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
        return builder.equal(builder.function("jsonb_extract_path_text", String.class, root.<String>get("title"), builder.literal(this.locale)), this.titleToSearch);
    }
}


@Service
public class ProductService {

    @Autowired
    private ProductRepository productRepository;

    public List<Product> findByTitle(String locale, String titleToSearch) {
        ProductSpecification cs = new ProductSpecification(locale, titleToSearch);
        return productRepository.find(cs);
        // Or using lambda expression - without the need of ProductSpecification class.
//      return productRepository.find((Root<ProductCategory> root, CriteriaQuery<?> query, CriteriaBuilder builder) -> {
//          return builder.equal(builder.function("jsonb_extract_path_text", String.class, root.<String>get("title"), builder.literal(locale)), titleToSearch);
//      });
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以在此处找到有关应如何使用Spring Data的其他答案.
希望有所帮助.


Geo*_*lou 6

您还可以使用FUNCJPQL 关键字来调用自定义函数,而不使用本机查询。
像这样的事情,

@Query(value = "SELECT t FROM my_table t "
        + "WHERE t.field_1=:field_1 AND t.field_2=1 AND t.field_3 IN :field_3 "
        + "AND FUNC('jsonb_extract_path_text', 'key', 'subkey')=:value")
List<Entity> getEntities(@Param("field_1") String field_1, @Param("field_3") Collection<Integer> field_3, @Param("value") String value);
Run Code Online (Sandbox Code Playgroud)

  • 如果您依赖专有的“jsonb_extract_path_text”函数,为什么不再使用本机查询很重要? (3认同)

col*_*ict 5

如果由于某种原因运算符被转换为问号,那么您应该尝试使用该函数。\doS+ #>>您可以在psql控制台中使用找到相应的函数。它告诉我们调用的函数是jsonb_extract_path_text。这将使您的查询:

@Query(value = "SELECT t.* " +
        "FROM my_table t " +
        "WHERE t.field_1 = ?1 " +
        "AND t.field_2 = 1 " +
        "AND t.field_3 IN ?2 " +
        "AND jsonb_extract_path_text(t.jsonb_field, '{key,subkey}') = ?3",
        nativeQuery = true)
Run Code Online (Sandbox Code Playgroud)