I'm having a problem getting this native query right against a postgres 9.4 instance.
My repository has a method:
@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);
But the logs show this:
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
And I get this exception:
Internal Exception: org.postgresql.util.PSQLException: No value specified for parameter 2.
I logged the parameters directly before method invocation, and they are all supplied.
I'm not sure why #>>
shows ?
in the log. Do I need to escape #>>
? Do I need to format the collection for IN
? Do I need to escape the json path?
When I execute the query directly against the db, it works. Example:
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'
The JSONB data type stores JSON (JavaScript Object Notation) data as a binary representation of the JSONB value, which eliminates whitespace, duplicate keys, and key ordering. JSONB supports GIN indexes.
The json data type stores an exact copy of the input text, which processing functions must reparse on each execution; while jsonb data is stored in a decomposed binary format that makes it slightly slower to input due to added conversion overhead, but significantly faster to process, since no reparsing is needed.
Spring Data JPA CrudRepository - findById() Method As the name depicts, the findById() method allows us to get or retrieve an entity based on a given id (primary key) from the DB. It belongs to the CrudRepository interface defined by Spring Data.
We can use @Query annotation to specify a query within a repository. Following is an example. In this example, we are using native query, and set an attribute nativeQuery=true in Query annotation to mark the query as native. We've added custom methods in Repository in JPA Custom Query chapter.
I found very helpful the Specification api from spring data.
Let's say we have an entity with name Product
and a property with name title
of type JSON(B).
I assume that this property contains the title of the Product in different languages. An example could be: {"EN":"Multicolor LED light", "EL":"Πολύχρωμο LED φώς"}
.
The source code below finds a (or more in case it is not a unique field) product by title and locale passed as arguments.
@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);
// });
}
}
You can find another answer about the way you should use the Spring Data here.
Hope that helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With