Spring 使用 PostgreSQL JSONB 进行 JPA 排序和分页
Spring JPA Sorting and Paging with PostgreSQL JSONB
我正在使用 Spring JPA 来管理我的 PostgreSQL 数据。此数据大量使用了 PostgreSQL 9.4
.
中的 jsonb
数据类型
我的 table(称为 jobtable
),简化后的样子是这样的:
id, bigint | data, jsonb
--------------------------------
1 | {"name": "Hello"}
2 | {"name": "Testing"}
使用 Spring JPA,我正在定义一个 CrudRepository
接口,以便对此 table 进行一些查询。对于 jsonb
特定的事情,我正在使用 nativeQuery = true
以便我可以使用此 PostgreSQL 类型。
例如,我可以这样查询我的属性:
@Query(
value = "select * from jobtable where data ->> 'name' = ?1",
nativeQuery = true)
JobEntity getJobByName(String name);
这个查询工作得很好。
当我尝试将分页与使用 jsonb
的本机查询一起使用时,我的问题出现了。我的查询是这样的:
@Query(
value = "select * from jobtable \n#pageable\n",
countQuery = "select count(*) from jobtable",
nativeQuery = true)
Page<JobEntity> getJobList(Pageable pageable);
我包含 Pageable
参数并这样调用函数:
Pageable pageable = new PageRequest(0, 10, Direction.DESC, "data ->> 'name'");
Page<JobEntity> results = myDao.getJobList(pageable);
此代码不起作用,并产生以下错误:
org.springframework.dao.InvalidDataAccessApiUsageException:
Sort expression 'data ->> 'name': DESC' must only contain property references or aliases used in the select clause. If you really want to use something other than that for sorting, please use JpaSort.unsafe(…)!
我不知道这个错误是怎么回事。我认为这与不正确地理解 PageRequest
对象中的 sortBy
参数有关,但我不确定当我打算对键进行排序时如何构建 PageRequest
对象在我的 jsonb
对象中。
我可以构建 Raw SQL 到 PostgreSQL 看起来像 select * from job order by data ->> 'jobId' desc limit 10
但我宁愿使用 Pageable
接口和 Spring JPA 所以我可以使用 @Query
符号,而不必自己在代码中明确定义任何内容。
尝试按如下方式创建 Pageable:
Pageable p = PageRequest.of(1,10,
JpaSort.unsafe(Direction.DESC, "data->>'name'"));
这应该可以消除异常。
对于那些在你使用 org.springframework.data.jpa.domain.Specification 的地方发现这个问题的人,这里是我如何让它在 toPredicate 方法中工作的方法
Expression exp = criteriaBuilder.function("jsonb_extract_path_text",
String.class,
root.get("data"),
criteriaBuilder.literal("name"));
switch (direction){
case ASC:
criteriaQuery.orderBy(criteriaBuilder.asc(exp));
break;
case DESC:
default:
criteriaQuery.orderBy(criteriaBuilder.desc(exp));
break;
}
我正在使用 Spring JPA 来管理我的 PostgreSQL 数据。此数据大量使用了 PostgreSQL 9.4
.
jsonb
数据类型
我的 table(称为 jobtable
),简化后的样子是这样的:
id, bigint | data, jsonb
--------------------------------
1 | {"name": "Hello"}
2 | {"name": "Testing"}
使用 Spring JPA,我正在定义一个 CrudRepository
接口,以便对此 table 进行一些查询。对于 jsonb
特定的事情,我正在使用 nativeQuery = true
以便我可以使用此 PostgreSQL 类型。
例如,我可以这样查询我的属性:
@Query(
value = "select * from jobtable where data ->> 'name' = ?1",
nativeQuery = true)
JobEntity getJobByName(String name);
这个查询工作得很好。
当我尝试将分页与使用 jsonb
的本机查询一起使用时,我的问题出现了。我的查询是这样的:
@Query(
value = "select * from jobtable \n#pageable\n",
countQuery = "select count(*) from jobtable",
nativeQuery = true)
Page<JobEntity> getJobList(Pageable pageable);
我包含 Pageable
参数并这样调用函数:
Pageable pageable = new PageRequest(0, 10, Direction.DESC, "data ->> 'name'");
Page<JobEntity> results = myDao.getJobList(pageable);
此代码不起作用,并产生以下错误:
org.springframework.dao.InvalidDataAccessApiUsageException:
Sort expression 'data ->> 'name': DESC' must only contain property references or aliases used in the select clause. If you really want to use something other than that for sorting, please use JpaSort.unsafe(…)!
我不知道这个错误是怎么回事。我认为这与不正确地理解 PageRequest
对象中的 sortBy
参数有关,但我不确定当我打算对键进行排序时如何构建 PageRequest
对象在我的 jsonb
对象中。
我可以构建 Raw SQL 到 PostgreSQL 看起来像 select * from job order by data ->> 'jobId' desc limit 10
但我宁愿使用 Pageable
接口和 Spring JPA 所以我可以使用 @Query
符号,而不必自己在代码中明确定义任何内容。
尝试按如下方式创建 Pageable:
Pageable p = PageRequest.of(1,10,
JpaSort.unsafe(Direction.DESC, "data->>'name'"));
这应该可以消除异常。
对于那些在你使用 org.springframework.data.jpa.domain.Specification 的地方发现这个问题的人,这里是我如何让它在 toPredicate 方法中工作的方法
Expression exp = criteriaBuilder.function("jsonb_extract_path_text",
String.class,
root.get("data"),
criteriaBuilder.literal("name"));
switch (direction){
case ASC:
criteriaQuery.orderBy(criteriaBuilder.asc(exp));
break;
case DESC:
default:
criteriaQuery.orderBy(criteriaBuilder.desc(exp));
break;
}