我有一个Postgres SQL查询,它将在jsonb type列内定义的键的值数组中执行搜索操作.

SELECT o.id
FROM customer c INNER JOIN order o
on c.id = o.c_id where EXISTS (
    SELECT 1
    FROM jsonb_array_elements_text(c.customer_data->'sid') AS value
    WHERE value = '3456' OR value='89110'
); 

在这里,sid是我的键,它有一组值.给定的查询将在值数组中执行深度搜索,如果键与这些值中的任何一个匹配,则返回记录.

我希望使用Criteria Builder和Criteria Query在Spring data JPA中生成等效项,以返回相同的结果.对此有什么建议会有帮助吗?

我的两个实体都是一对多关系的连接,我正在努力实现上面的查询结果:

public List<Long> findCustomerIds(EntityManager entityManager,String key, List<String> sidValues) {
    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    CriteriaQuery<Long> cq = cb.createQuery(Long.class);
    Root<Customer> cRoot = cq.from(Customer.class);
    
    // Join between Customer and Order
    Join<Customer, Order> oJoin = cRoot.join("orders");

    // Subquery to handle JSONB array elements condition
    Subquery<String> subquery = cq.subquery(String.class);
    Root<Customer> subRoot = subquery.from(Customer.class);
    Path<Object> subCustomerDataPath = subRoot.get("customerData");
    Path<String> subSidPath = cb.function("jsonb_array_elements_text", String.class, subCustomerDataPath.get(key));

    subquery.select(subRoot.get("id"))
            .where(cb.or(
                sidValues.stream()
                              .map(sid -> cb.equal(cb.upper(subSidPath), sid.toUpperCase()))
                              .toArray(Predicate[]::new)
            ));

    cq.select(cRoot.get("id"))
      .where(cb.equal(oJoin.get("customer"), cRoot), cb.exists(subquery));

    return entityManager.createQuery(cq).getResultList();
}

该问题存在于给定的代码部分中:

// Subquery to handle JSONB array elements condition
Subquery<String> subquery = cq.subquery(String.class);
Root<Customer> subRoot = subquery.from(Customer.class);
Path<Object> subCustomerDataPath = subRoot.get("customerData");
Path<String> subSidPath = cb.function("jsonb_array_elements_text", String.class, subCustomerDataPath.get(key));
subquery.select(subRoot.get("id"))
.where(cb.or(
sidValues.stream()
   .map(sid -> cb.equal(cb.upper(subSidPath), sid.toUpperCase()))
                              .toArray(Predicate[]::new)
));

我在子查询部分得到了Illegal attempt to dereference path source [null.customerData]个错误.我不知道我的代码中有什么错误.

作为参考,我在Entity中以以下方式定义了jsonb字段,因为所有键和值都以以下方式存储:

@Type(type = "jsonb")
@Column(name = "customer_data",columnDefinition = "jsonb")
private Map<String,List<String>> customerData = new HashMap<>();

如果你对此有任何替代的方法或建议,将是有帮助的.首先要感谢您的帮助.

推荐答案

在Hibernate 标准中应用该函数时,jsonb_array_element_text表达式存在一些问题.

给定的查询可以作为上述查询的替代,以获得相同的结果:

SELECT o.id
FROM customer c INNER JOIN order o
on c.id = o.c_id where LIKE c.customer_data->'sid' LIKE '%"3456"%' OR c.customer_data->'sid' LIKE '%"89110"%'

注意:在内部,存储的数组值将被转换为字符串,并对该字符串执行搜索操作.If the value is array of string than make sure to pass the quotes otherwise it will not work as expected.

要使用Hibernate标准实现相同的功能,请使用jsonb_extract_path_text函数.

public List<Long> findCustomerIds(EntityManager entityManager,String key, List<String> sidValues) {
    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    CriteriaQuery<Long> cq = cb.createQuery(Long.class);
    Root<Customer> cRoot = cq.from(Customer.class);
    
    // Join between Customer and Order
    Join<Customer, Order> oJoin = cRoot.join("orders");

    // Constructing the WHERE clause predicates
    Predicate[] predicates = new Predicate[values.size()];
    for (int i = 0; i < values.size(); i++) {
predicates[i]= cb.like(cb.function("jsonb_extract_path_text", String.class, oJoin.get("customerData"), cb.literal(key)),"%\"" + values.get(i) + "\"%");
 }

    // Applying OR condition
    requestPredicate= cb.or(predicates);

    cq.select(cRoot.get("id")).where(requestPredicate);


    return entityManager.createQuery(cq).getResultList();
}

如果值以字符串格式存储在列表中,则向外部传递要搜索的值的引号,否则将按预期工作.

Postgresql相关问答推荐

Postgs密码重置问题

在输入稍有错误的PostgreSQL表中进行快速字符串搜索

PostgreSQL解释分析实际时间不加总

PostgreSQL(container)中使用80K子分区表处理共享内存不足错误

为什么在使用PostGIS时,英国郡的几何图形会出现在几内亚湾?

ANTLR4 PostgreSQL语法被 destruct 了吗?

单个WAL文件中的操作会影响哪些表和多少行

在Postgre中的链接服务器上执行远程查询

如何在 kubernetes 中安全地重启 postgresql 容器?

如何判断上次在 TimescaleDB 上运行连续聚合作业(job)的时间

PG::UndefinedTable:错误:relation "active_storage_blobs" does not exist

运算符不存在:integer = integer[] 在使用 ANY 的查询中

如何使用 ActiveRecord json 字段类型

保存 geodjango PointField 时出错

如何使用 pg_dump 或 psql 从 *.sql 恢复 PostgreSQL 表?

我应该同时指定 INDEX 和 UNIQUE INDEX 吗?

Postgres UPDATE with ORDER BY,怎么做?

使用 RPostgreSQL 写入特定模式

如何从 PostgreSQL 中的 Json 数组中获取元素

如何使用 postgresql 按计数排序?