Как верно создать поиск в JSONB с использованием Criteria API
у меня вопрос как можно работать с jsonb колонкой, в которой массив json элементов, например колонка имеет такие данные [{"key1": "value1"}, {"key2": "value2"},...].
Использую postgresql, hibernate, jpa
как я могу создать toPredicate чтобы получить отфильтрованные данные, которые имеют в значении, например value1?
Я пробивал сделать вот так, но данный код дает исключение при использовании:
public class MyEntityWithValue implements Specification<MyEntity> {
private String valueToFind;
public MyEntityWithValue(String valueToFind) {
this.valueToFind= valueToFind;
}
@Override
public Predicate toPredicate(Root<MyEntity> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
if (valueToFind== null || valueToFind.isEmpty()) {
return builder.conjunction();
}
Subquery<MyEntity> subquery = query.subquery(MyEntity.class);
Root<MyEntity> subRoot = subquery.from(MyEntity.class);
Expression<Boolean> jsonContains = builder.function(
"json_contains",
Boolean.class,
subRoot.get("columnWithJsonB"),
builder.literal("{\"key1\":\"" + valueToFind + "\"}")
);
subquery.select(subRoot)
.where(jsonContains);
return builder.exists(subquery);
}
}
unexpected AST node: function (json_contains)
использую я так:
public class MyCriterion {
private String columnWithJsonB;
}
private Specification<MyEntity> createSpecification(MyCriterion criterion) {
Specification<MyEntity> spec = Specification.where(new MyEntityWithValue (criterion.getColumnWithJsonB()));
return spec;
}
@Override
public Page<MyEntityResponseDTO> findAllWithPaginationAndSorting(MyCriterion myCriterion, int page, int perPage, List<String> sortBy, String sortOrder) {
Pageable pageable = PageRequest.of(page - 1, perPage, Sort.by(createSortOrder(sortBy, sortOrder)));
Page<MyEntity> mye = myERepo.findAll(createSpecification(myCriterion), pageable);
return mye.map(MyEntityResponseDtoMapper::toDto);
}
Буду благодарен за любую подсказку
Ответы (1 шт):
Попробуйте такой вариант подогнать под себя:
@Override
public Predicate toPredicate(Root root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.equal(
cb.function("jsonb_extract_path_text", String.class, root.get("attributes"), cb.literal(key)),
value
);
}
Добавлю что поле JSONB можно представить не только как String
@Column(columnDefinition = "jsonb")
private String attributes;
но и как объект
@Column(columnDefinition = "jsonb")
private MyObject attributes;
где
public record MyObject(String key1, String key2) {}
Источник: https://www.baeldung.com/spring-data-jpa-querying-jsonb-columns