このネイティブクエリを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パスをエスケープする必要がありますか?
Dbに対して直接クエリを実行すると、機能します。例:
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'
春のデータから 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 here の使用方法に関する別の答えを見つけることができます。
それが役立つことを願っています。
これは古いトピックかもしれませんが、ここではjsonbでスプリング仕様を使用してフィールドごとに検索しています。
「LIKE」で検索する場合は、次のコードを使用して分離のように作成する必要があります。
final Predicate likeSearch = cb.disjunction();
その後、あなたのオブジェクトにアドレスであるjsonbフィールドがあり、アドレスには5つのフィールドがあると仮定しましょう。これらすべてのフィールドを検索するには、すべてのフィールドに「LIKE」式を追加する必要があります。
for (String field : ADDRESS_SEARCH_FIELDS) {
likeSearch.getExpressions().add(cb.like(cb.lower(cb.function("json_extract_path_text", String.class,
root.get("address"), cb.literal(field))), %searchKey%));
}
ここで、cbは同じcriteriaBuilderです。 %searchKey%は、住所フィールドで検索するものです。
お役に立てれば。
FUCT
JPQLキーワークを使用して、カスタム関数を呼び出し、ネイティブクエリを使用することもできます。
このようなもの、
@Query(value = "SELECT t FROM my_table t "
+ "WHERE t.field_1=:field_1 AND t.field_2=1 AND t.field_3 IN :field_3 "
+ "AND FUNC('jsonb_extract_path_text', 'key', 'subkey')=:value")
List<Entity> getEntities(@Param("field_1") String field_1, @Param("field_3") Collection<Integer> field_3, @Param("value") String value);
演算子が何らかの理由で疑問符に変換されている場合は、代わりに関数を使用してみてください。 psqlコンソールで\doS+ #>>
を使用して、対応する関数を見つけることができます。呼び出された関数はjsonb_extract_path_text
であることがわかります。これはあなたのクエリになります:
@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 jsonb_extract_path_text(t.jsonb_field, '{key,subkey}') = ?3",
nativeQuery = true)
この方法に従わないことをお勧めします。一般的なCRUD方法に従うことをお勧めします(Spring Data Rest Mavenプラグインの場合、StrongLoop Loopbackの方法で高度な自動生成DAOメソッドにも取り組んでいますが、現時点では実験的なものです)。しかし、このJSONで、次に何をすべきか... @Documentアノテーションを介してSpring DataでMongoDB JSON処理に似たものを探していますが、これはまだ使用できません。しかし、他の方法があります:-)
一般的には、JSONユーザータイプ(UserTypeインターフェイス)の実装についてです。
public class YourJSONBType implements UserType {
最後に、実装したユーザータイプの仕様でJPAクラスを拡張する必要があります。
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@TypeDef(name = "JsonbType", typeClass = YourJSONBType.class)
public class Person {
@Id
@GeneratedValue
private Long id;
@Column(columnDefinition = "jsonb")
@Type(type = "JsonbType")
private Map<String,Object> info;
}
他の関連記事をここで見てください: PostgreSQL JSON列をHibernate値型にマッピング
完全な実装例はここにあります:
同様ですが、少し異なる例がここにあります: http://www.wisely.top/2017/06/27/spring-data-jpa-postgresql-jsonb/?d=1