Overview
このガイドでは、MongoDB Extension for Hibernate ORM を使用して、クエリの結果をソート、スキップ、リミット、グループする方法を学ぶことができます。
結果を並べ替える
クエリ ステートメントで order by 句を使用すると、指定したフィールドの値でクエリ結果をソートできます。デフォルトでは 、order by 句はドキュメントを昇順でソートします。ドキュメントを降順で並べ替えるには、フィールド名に desc キーワードを追加します。
次の例では、sample_mflix.moviesコレクションから一致するドキュメントを検索し、yearフィールドで降順に並べ替えます。
var sortResult = session.createQuery("from Movie where title = :t order by year desc", Movie.class) .setParameter("t", "Cinderella") .getResultList();for (var m : sortResult) { System.out.println("Title: " + m.getTitle() + ", Year: " + m.getYear());}var sortResult = entityManager.createQuery("select m from Movie m where m.title = :t order by m.year desc", Movie.class) .setParameter("t", "Cinderella") .getResultList();for (var m : sortResult) { System.out.println("Title: " + m.getTitle() + ", Year: " + m.getYear());}結果をスキップする
setFirstResult() メソッドをクエリに連結することで、クエリ結果内の指定した数のドキュメントをスキップできます。スキップする初期ドキュメントの数をこのメソッドの引数として渡します。
次の例では、前の例と同じクエリを実行しますが、結果内の最初の一致するドキュメントをスキップします。
var skipResult = session.createQuery("from Movie where title = :t order by year desc", Movie.class) .setParameter("t", "Cinderella") .setFirstResult(1) .getResultList();for (var m : skipResult) { System.out.println("Title: " + m.getTitle() + ", Year: " + m.getYear());}var skipResult = entityManager.createQuery("select m from Movie m where m.title = :t order by m.year desc", Movie.class) .setParameter("t", "Cinderella") .setFirstResult(1) .getResultList();for (var m : skipResult) { System.out.println("Title: " + m.getTitle() + ", Year: " + m.getYear());}結果を制限する
クエリが返すドキュメント数を制限するには、setMaxResults() メソッドをクエリに連結します。返されるドキュメントの最大数をこのメソッドの引数として渡します。
次の例では、ソートの例と同じクエリを実行しますが、結果には一致するドキュメントが最大 2 つ返されます。
var limitResult = session.createQuery("from Movie where title = :t order by year desc", Movie.class) .setParameter("t", "Cinderella") .setMaxResults(2) .getResultList();for (var m : limitResult) { System.out.println("Title: " + m.getTitle() + ", Year: " + m.getYear());}var limitResult = entityManager.createQuery("select m from Movie m where m.title = :t order by m.year desc", Movie.class) .setParameter("t", "Cinderella") .setMaxResults(2) .getResultList();for (var m : limitResult) { System.out.println("Title: " + m.getTitle() + ", Year: " + m.getYear());}あるいは、次のコードに示すように、HQL または JQL のステートメントで limit 句を使用して、クエリが返すドキュメントの数を制限することもできます。
var limitClauseResult = session.createQuery("from Movie where title = :t order by year desc limit 2", Movie.class) .setParameter("t", "Cinderella") .getResultList();var limitClauseResult = entityManager.createQuery("select m from Movie m where m.title = :t order by m.year desc limit 2", Movie.class) .setParameter("t", "Cinderella") .getResultList();結果をグループ化
クエリステートメントで group by 句を使用すると、共通の値を持つドキュメントを単一の結果行に折りたたむことができます。Hibernate ORM 拡張機能は、group by 句を MongoDB の $group ステージに変換します。このステージでは、各グループ化キーが _id フィールドのサブフィールドになります。
重要
グループ化キーの要件
グループ化されたクエリの select、having、または order by 句で参照されるすべてのフィールドは、グループ化キーであるか、その一部である必要があります。$group ステージが生成しないフィールドを参照すると、Hibernate ORM 拡張機能は FeatureNotSupportedException をスローします。
グループ化されたクエリでも、SELECT DISTINCT は使用できません。フィールドの個別の値のみを要約するには、「 個別の値を要約する 」を参照してください。
フィールド値でグループ化
1つ以上のフィールドの値で結果をグループ化するには、group by句にフィールドをリストします。複数のフィールドでグループ化するには、フィールド名をカンマで区切ります。
この例では、次の操作を実行します。
sample_mflix.moviesコレクションからtitle値が"Hairspray"であるドキュメントを検索します。yearフィールドで映画をグループ化し、リリース年ごとに1行を返します。year値に基づいて結果を昇順で並べ替えます。
var groupResult = session.createQuery( "select year from Movie where title = :title group by year order by year", Integer.class) .setParameter("title", "Hairspray") .getResultList();for (var year : groupResult) { System.out.println("Year: " + year);}var groupResult = entityManager.createQuery( "select m.year from Movie m where m.title = :title group by m.year order by m.year", Integer.class) .setParameter("title", "Hairspray") .getResultList();for (var year : groupResult) { System.out.println("Year: " + year);}Hibernate ORM 拡張機能は、このクエリを次のパイプラインに変換します。where 句は、グループ化の前に実行される $match ステージになります。order by 句は、グループ化キーでソートする $sort ステージになります。
[ { "$match": { "title": { "$eq": "Hairspray" } } }, { "$group": { "_id": { "year": "$year" } } }, { "$sort": { "_id.year": 1 } }, { "$project": { "_id#year": "$_id.year", "_id": 0 } }]計算された式でグループ化する
グループ化キーは、フィールド参照ではなく、計算された式にできます。Hibernate ORM 拡張機能は、生成された _id サブフィールド k<n> に式を保存します。select 節または having 節で同じ式を書き込み (write)すると、Hibernate ORM 拡張機能はその式を再計算するのではなく、そのサブフィールドに変換します。
Hibernate ORM拡張機能は、式とグループ化キーを同一に書き込み (write)た場合にのみ、それらを一致させます。例として、キー year + 1 は 1 + year の出現と一致しません。
計算された式キーで並べ替えることもできます。order by 句の式は、group by 句に書き込み (write)するのとまったく同じように書き込み (write)してください。
次の例では、titleが"Hairspray"であるドキュメントをリリースされた年代ごとにグループ化し、結果を昇順で並べ替えます。
var groupExpressionResult = session.createQuery( "select year / 10 * 10 from Movie where title = :title group by year / 10 * 10 order by year / 10 * 10", Integer.class) .setParameter("title", "Hairspray") .getResultList();for (var decade : groupExpressionResult) { System.out.println("Decade: " + decade);}var groupExpressionResult = entityManager.createQuery( "select m.year / 10 * 10 from Movie m where m.title = :title group by m.year / 10 * 10 order by m.year / 10 * 10", Integer.class) .setParameter("title", "Hairspray") .getResultList();for (var decade : groupExpressionResult) { System.out.println("Decade: " + decade);}Hibernate ORM 拡張機能は、このクエリを次のパイプラインに翻訳します。このパイプラインでは、$sort ステージと $project ステージが、式を再計算する代わりに _id.k0 からグループ化キーを読み取ります。
[ { "$match": { "title": { "$eq": "Hairspray" } } }, { "$group": { "_id": { "k0": { "$multiply": [ { "$toInt": { "$divide": [ "$year", 10 ] } }, 10 ] } } } }, { "$sort": { "_id.k0": 1 } }, { "$project": { "#c_1": "$_id.k0", "_id": 0 } }]グループ化キーを含む計算式を選択することもできます。この場合、Hibernate ORM拡張機能はキーでグループ化し、$projectステージでキーから式を計算します。
計算された式について学ぶには、「Specify a クエリ」ガイドの「Use Computed Expressions」セクションを参照してください。
グループ化された結果をフィルター
結果からグループを除くには、having 句を使用します。Hibernate ORM 拡張機能は、having 句を使用してグループ化キーをフィルターします。and 演算子と or 演算子を使用して、複数の条件を組み合わせることができます。
この例では、次の操作を実行します。
sample_mflix.moviesコレクションから"Hairspray"件の映画を検索します。yearフィールドで映画をグループ化し、リリース年ごとに1行を返します。2000より大きいyear値のみを含むようにグループをフィルターします。結果を年で昇順に並べ替えます。
var havingResult = session.createQuery( "select year from Movie where title = :title group by year having year > 2000 order by year", Integer.class) .setParameter("title", "Hairspray") .getResultList();for (var year : havingResult) { System.out.println("Year: " + year);}var havingResult = entityManager.createQuery( "select m.year from Movie m where m.title = :title group by m.year having m.year > 2000 order by m.year", Integer.class) .setParameter("title", "Hairspray") .getResultList();for (var year : havingResult) { System.out.println("Year: " + year);}Hibernate ORM 拡張機能は、このクエリを次のパイプラインに変換します。where 句は、グループ化の前に実行される $match ステージになります。having 句は、グループ化の後に実行され、グループ化キーでフィルター処理を行う 2 番目の $match ステージになります。
[ { "$match": { "title": { "$eq": "Hairspray" } } }, { "$group": { "_id": { "year": "$year" } } }, { "$match": { "_id.year": { "$gt": 2000 } } }, { "$sort": { "_id.year": 1 } }, { "$project": { "_id#year": "$_id.year", "_id": 0 } }]詳細情報
MongoDBデータに対してその他の操作を行う方法の詳細については、CRUD 操作ガイドを参照してください。
HQL と JQL を使用してクエリを実行する方法の詳細については、非表示の ORM ドキュメントの「非表示のクエリ言語へのガイド」を参照してください。