JavaでPostgreSQLにJSONを保存し、取得する
json型というものがあるので、その特徴を踏まえて今回必要な機能をMinumumに実現するにはどうすべきか検討してみた。
まず、テーブル定義でJSONを保存するには以下が候補としてありそうだった。
text型
json型
jsonb型
とりあえずJSONを保存するし、json型/jsonb型から検討を始めた。
保存
特徴としては以下のような感じ。
json型
jsonb型より前にPostgreSQLに実装された
JSONを文字列として保存する
保存時にJSONとして正しいかのパースがかかる
保存前の形をそのまま保存する(空白などは除去されない)
取得時にもパースされる
検索時にJSONのkeyは検索対象とならず、valueの方のみ検索可能
jsonb型
json型より遅れて実装された上位互換的なもの
JSONをそのままオブジェクトとして保って保存される(バイナリで保存される)
保存時にJSONとして正しいかのパースがかかる
空白などバイナリ化されて削ぎ落とされるものがあるため、保存前と全く同じ形で保存しているわけではない
取得時はパースされない(検索効率がjson型よりもよい)
検索時にJSONのkeyは検索対象とならず、valueの方のみ検索可能
cf) https://www.postgresql.jp/sites/default/files/2016-12/B5_PGCon2014-JSONB-datatype-20141205.pdf
いまとなってはjson型を積極的に選択する理由はなく、基本的にjsonb型を選択すればすべての恩恵がついてくる、というものらしい。
使い所としてはJSONをそのまま保存して全文検索的に検索かける要件、かつ、そこまでデータ量が多くない要件の場合にマッチしそうな印象。(ガチで全文検索したいなら、検索エンジンを別途構築したほうがよいはず。)
続いてtext型。
text型
最大長を規定しない可変長文字列
JSONとして認識しないため、検索条件に指定した場合、keyもvalueも検索対象となる
まぁ平たく言うならブログの本文を突っ込んでおくカラム。
もちろん最大長はホストOSやDBの仕様制約にひっかかって青天井ってことはないはずだけど、基本的にいくらでも入る。
中身を検証しないので、「JSONである」という制約が不要な場合はこちらでもよさそう。
取得
Spring Bootを使っているとデフォルトでHibernateをORマッパーに使用するので、そこでアノテーションベースの使用感がよいものが使いやすい。試してみるとそれぞれ以下のような感じだった。
json型
デフォルトの実装では無理
code:Java
// Javaのすごい人のライブラリを追加する
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-52</artifactId>
<version>2.2.2</version>
</dependency>
// Entityクラス
import com.vladmihalcea.hibernate.type.json.JsonBinaryType
@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
public class HogeEntity {
...
@Type(type = "jsonb")
@Column(name = "json", columnDefinition = "json")
private JsonNode json;
...
}
jsonb型
デフォルトの実装では無理
(コードはjson型と同じでおk)
text型
Stringでマッピングすればおk
code:Java
// Entityクラス
...
@Column(name = "json")
private String json;
...
//
json型/jsonb型はデフォルトではサポートされておらず、外部ライブラリもしくは自作する必要がありそう。
text型はvarcharとかと一緒でStringがそのまま使えるのでライブラリなどに頼る必要はない。
あとは要件次第って感じかなー。