如何使用 spring data jpa 查询 jsonb 列?

新手上路,请多包涵

我在针对 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);

但日志显示:

 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

我得到这个例外:

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

我在方法调用之前直接记录了参数,它们都已提供。

我不确定为什么 #>> ? 。我需要转义 #>> 吗?我是否需要为 IN 格式化集合?我需要转义 json 路径吗?

当我直接对数据库执行查询时,它起作用了。例子:

 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'

原文由 Josh C. 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 504
1 个回答

我发现来自 spring 数据的 Specification api 非常有用。

假设我们有一个名称为 Product 的实体和一个名称为 title 的 JSON(B) 类型的属性。

我假设此属性包含不同语言的产品标题。例如: {"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);
//      });
    }
}

您可以 在此处 找到有关应如何使用 Spring Data 的方式的另一个答案。

希望有所帮助。

原文由 Georgios Syngouroglou 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题