Overview
このガイドでは、Hibernate ORM用MongoDB拡張機能を使用して、MongoDBデータベースでネイティブクエリを実行する方法を学ぶことができます。Hibernate クエリ言語 (HQL) や Jakarta Persistence クエリ言語 (JPQL) の代わりに、ネイティブクエリを使用すると、MongoDB クエリ言語 (MQL) を使用してクエリを指定できます。MQLは、MongoDBのドキュメントベースのモデルと交流するために設計されたクエリ構文です。
Hibernate ORM の createQuery() メソッドは、一部のMongoDBクエリ機能をサポートしていません。createNativeQuery() メソッドを使用すると、MQLでデータベースクエリを指定し、Hibernate ORM 拡張機能の一部の運用上の制限をバイパスできます。
また、クエリ機能を拡張するために、MongoClientオブジェクトに対してクエリを直接実行することもできます。
サンプル データ
このガイドの例では、Atlasサンプルデータセットの sample_mflix.moviesコレクションを表す Movie エンティティを使用します。Movie エンティティには次の定義があります。
import com.mongodb.hibernate.annotations.ObjectIdGenerator;import org.bson.types.ObjectId;import java.util.List;
import jakarta.persistence.Entity;import jakarta.persistence.Id;import jakarta.persistence.Table;
@Entity@Table(name = "movies")public class Movie { @Id @ObjectIdGenerator private ObjectId id; private String title; private String plot; private int year; private int runtime; private List<String> cast; private List<String> directors;
public Movie(String title, String plot, int year, int runtime, List<String> cast, List<String> directors) { this.title = title; this.plot = plot; this.year = year; this.runtime = runtime; this.cast = cast; this.directors = directors; }
public Movie() {
}
public ObjectId getId() { return id; }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public String getPlot() { return plot; }
public void setPlot(String plot) { this.plot = plot; } public int getYear() { return year; }
public void setYear(int year) { this.year = year; }
public int getRuntime() { return runtime; }
public void setRuntime(int runtime) { this.runtime = runtime; }
public List<String> getCast() { return cast; }
public void setCast(List<String> cast) { this.cast = cast; }
public List<String> getDirectors() { return directors; }
public void setDirectors(List<String> directors) { this.directors = directors; }}Hibernetes ORM 用のMongoDB拡張機能を使用してこのMongoDBサンプルコレクションと交流するJavaアプリケーションを作成する方法については、Get Started チュートリアルを参照してください。
注意
永続性コンテキスト
Hibernate ORM を有効にしてデータベースと交流するには、Hibernate Session または Jakarta 永続性 EntityManager を使用して永続性コンテキスト内で操作を実行する必要があります。このガイドの例では、Session を使用しています。永続性コンテキストの詳細については、トランザクションとセッションのガイドを参照してください。
ネイティブクエリを実行する
ネイティブのMongoDBクエリを実行するには、クエリするコレクションとクエリ条件を集計パイプラインで含むMongoDBクエリ言語(MQL)ステートメントを指定します。
MQLステートメントは次の形式です。
String mqlSyntax = """{ aggregate: "<collection to query>", pipeline: [ <aggregation pipeline stages> ]}""";重要
$ プロジェクトステージの要件
MQLステートメントの集計パイプラインには、$projectステージを含める必要があります。クエリドキュメントをエンティティインスタンスとして返すには、_idフィールドを含め、$projectステージで各エンティティフィールドを指定する必要があります。Hibernate ORM拡張機能は、プロジェクトするフィールドを返し、省略した場合は_idを抑制します。_idを省略したエンティティバインドクエリは、エンティティ識別子が_idにマップされるため、Unknown column label [_id]で失敗する可能性があります。識別子を利用可能な状態に保つには、_id: 1をプロジェクトします。
そして、MQL ステートメントを createNativeQuery() メソッドに渡します。
ネイティブクエリを使用して、次の操作を実行できます。
重要
拡張 JSON 構文が必要
ネイティブクエリは、Extended JSON v2形式で書き込み (write)する必要があります。Hibernate ORM拡張機能は、ネイティブクエリでのシングルクォートやMongoDB Server shellの正規表現構文(/pattern/)をサポートしていません。たとえば、正規表現でクエリを実行するには、/pattern/の代わりに$regularExpression Extended JSON型を使用します。
ドキュメント フィールドのフィルターとソート
この例ではMQLステートメントを createNativeQuery() メソッドに渡して、sample_mflix.moviesコレクションに対してネイティブクエリを実行します。このコードでは、次の集計パイプライン ステージを指定します。
$match: タイトルフィールドの値が のドキュメントをフィルター"The Parent Trap"$sort: 一致するドキュメントをyearフィールドで降順に並べ替えます$project:Movieエンティティで定義されている各ドキュメントフィールドを返します
String nativeQuery = """{ aggregate: "movies", pipeline: [ { $match: { title: { $eq: "The Parent Trap" } } }, { $sort: { year: -1 } }, { $project: { _id: 1, title: 1, plot: 1, year: 1, runtime: 1, cast: 1 } } ]}""";
var results = session.createNativeQuery(nativeQuery, Movie.class) .getResultList();
for (Movie movie : results) { System.out.println("Title: " + movie.getTitle() + ", Year: " + movie.getYear());}算術演算子の使用
注意
ネイティブクエリは、Hibernate ORM拡張機能でサポートされていない算術操作に最適です。Hibernate ORM拡張機能がサポートする算術演算子の詳細については、機能互換性ページの「クエリサポート」セクションを参照してください。
次の例では、 sample_mflix.moviesコレクションに対して次のアクションを実行するネイティブ クエリを実行します。
yearの値が2000より大きく、かつruntimeフィールドが存在するドキュメントを検索するために、$matchステージを指定しますruntimeHoursという新しいフィールドを追加するには$addFieldsステージを指定します$divide算術演算子を使用して、新しいruntimeHoursフィールドのruntime値を 分から時間に変換しますMovieエンティティで定義された各ドキュメントフィールドを返す$projectステージを指定します(_idフィールドを含む)。更新された各ドキュメントの
title値を出力します
String nativeQuery = """{ aggregate: "movies", pipeline: [ { $match: { year: { $gt: 2000 }, runtime: { $exists: true } } }, { $addFields: { runtimeHours: { $divide: [ "$runtime", 60 ] } }}, { $project: { _id: 1, title: 1, plot: 1, year: 1, runtime: 1, cast: 1, runtimeHours: 1 }} ]}""";
var results = session.createNativeQuery(nativeQuery, Movie.class) .getResultList();
for (Movie result : results) { System.out.println("Added field to movie: " + result.getTitle());}Tip
算術演算子
Hibernate と MongoDB 演算子の詳細については、次のリソースを参照してください。
MongoDB 検索クエリを実行する
ネイティブ クエリを実行すると、データベースに対してMongoDB 検索クエリを実行することができます。これは、データに対するきめ細かなテキスト検索です。これらのクエリは、テキスト フレーズの一致、関連性の結果のスコアリング、一致の強調表示など、高度な検索機能を提供します。
重要
トランザクション内ではMongoDB 検索クエリを実行できません。
検索クエリを指定するには、クエリを実行するフィールドをカバーする検索インデックスを作成します。次に、$search または $searchMeta ステージを含む集計パイプラインをcreateNativeQuery() メソッドに渡します。
Tip
MongoDB Search
MongoDB Search クエリとインデックスの詳細については、 MongoDB Serverマニュアルの「 MongoDB Search の概要 」を参照してください。
この例では、$searchパイプラインステージをcreateNativeQuery()メソッドに渡して検索クエリを実行します。このコードは、次のアクションを実行します。
plotフィールドをカバーする検索インデックスを指定します。<indexName>プレースホルダーを 検索インデックス名に置き換えてください。plot値に対し、3単語以下の文字列"whirlwind romance"が含まれるドキュメントのクエリMovieエンティティで定義された各ドキュメントフィールドを返す$projectステージを指定します(_idフィールドを含む)。一致するドキュメントの
titleとplotの値を出力します
String nativeQuery = """{ aggregate: "movies", pipeline: [ { $search: { index: "<indexName>", phrase: { path: "plot", query: "whirlwind romance", slop: 3 } } }, { $project: { _id: 1, title: 1, plot: 1, year: 1, runtime: 1, cast: 1 } } ]}""";
var results = session.createNativeQuery(nativeQuery, Movie.class) .getResultList();
for (Movie result : results) { System.out.println("Title: " + result.getTitle() + ", Plot: " + result.getPlot());}ネイティブクエリでパラメータを使用する
MQL ステートメント内では、名前付きパラメータ (:name) または序数パラメータ (?1) を使用して値を指定できます。次の例では、title パラメーター値を名前付きパラメーターまたは序数パラメーターとして提供し、その後、setParameter() を使用してパラメーター値を提供する方法を示します。
String nativeQuery = """{ aggregate: "movies", pipeline: [ { $match: { title: { $eq: :movieTitle } } }, { $sort: { year: -1 } }, { $project: { _id: 1, title: 1, plot: 1, year: 1, runtime: 1, cast: 1 } } ]}""";
var results = session.createNativeQuery(nativeQuery, Movie.class) .setParameter("movieTitle", "The Parent Trap") .getResultList();
for (Movie movie : results) { System.out.println("Title: " + movie.getTitle() + ", Year: " + movie.getYear());}String nativeQuery = """{ aggregate: "movies", pipeline: [ { $match: { title: { $eq: ?1 } } }, { $sort: { year: -1 } }, { $project: { _id: 1, title: 1, plot: 1, year: 1, runtime: 1, cast: 1 } } ]}""";
var results = session.createNativeQuery(nativeQuery, Movie.class) .setParameter(1, "The Parent Trap") .getResultList();
for (Movie movie : results) { System.out.println("Title: " + movie.getTitle() + ", Year: " + movie.getYear());}MongoClient 操作を実行する
createQuery() メソッドも createNativeQuery() メソッドもサポートしていないデータベース操作を実行する場合は、Javaアプリケーションで直接 MongoClient オブジェクトを操作できます。MongoClient を使用すると、 MongoDB Java Sync Driver の 機能にアクセスできます。
Javaドライバーを使ってMongoDBと交流する方法を学ぶには、MongoDB Javaドライバーのドキュメントを参照してください。
MongoClient によるインデックスの作成
Hibernate ORM 拡張機能を使用してコレクションにインデックスを作成することはできませんが、MongoClient をインスタンス化してJavaドライバーの createIndex() メソッドを使用できます。次のコードを使用することで、sample_mflix.moviesコレクションに titleフィールドインデックスが作成されます。
// Replace the <connection URI> placeholder with your MongoDB connection URIString uri = "<connection URI>";MongoClient mongoClient = MongoClients.create(uri);MongoDatabase db = mongoClient.getDatabase("sample_mflix");MongoCollection<Document> collection = db.getCollection("movies");
String indexResult = collection.createIndex(Indexes.ascending("title"));System.out.println(String.format("Index created: %s", indexResult));Javaドライバーを使用してインデックスを作成する方法の詳細については、Javaドライバーのドキュメントのインデックスガイドを参照してください。
詳細情報
このガイドで説明されているクエリ言語の詳細については、次のリソースを参照してください。
非表示 ORM ドキュメントの「非表示クエリ言語のガイド」
MongoDB Serverマニュアルの MongoDBクエリ言語リファレンス