Overview
このガイドでは、MongoDB との照合を使用して、クエリまたは集計操作の結果を string 値で並べ替える方法を説明します。 照合は、特定の言語とロケールに適用される文字の順序付けとマッチング ルールのセットです。
照合について詳しくは、このガイドの次のセクションを参照してください。
重要
プロジェクトリ アクター ライブラリ
このガイドでは、プロジェクト Reactive ライブラリを使用して、 Java Reactive Streams ドライバー メソッドによって返された Publisher インスタンスを消費します。Project Reactive ライブラリとその使用方法の詳細については、React ドキュメントの使用開始を参照してください。このガイドでは Project React ライブラリ メソッドをどのように使用しているかについて詳しくは、 「 MongoDBへのデータの書込み 」ガイドを参照してください。
MongoDB の照合
MongoDB は、デフォルトで バイナリ照合 を使用して string をソートします。バイナリ照合では、ASCII 標準 文字値を使用して string を比較および順序付けます。特定の言語とロケールには、ASCII 文字値とは異なる特定の文字順序付け規則があります。
たとえば、カナダフランス語では、先行するすべての文字が同じ場合、右端のアクセント記号(発音区別符号)によって string の順序が決まります。 次のカナダフランス語の単語について考えてみます。
コピー
coté
côte
côté
バイナリ照合を使用する場合、MongoDB はそれらを次の順序でソートします。
cote coté côte côté
カナダ フランス語の照合を使用する場合、MongoDB はそれらを次の順序でソートします。
cote côte coté côté
照合の指定方法
MongoDB は、ほとんどのCRUD操作と集計で照合をサポートしています。サポートされている操作の完全なリストについては、 MongoDB Serverマニュアルの「 照合をサポートする操作 」を参照してください。
ロケール コードとオプションのバリアントを次の string 形式で指定できます。
"<locale code>@collation=<variant code>"
次の例では、"de"ロケールコードと "phonebook" バリアント コードを指定します。
"de@collation=phonebook"
バリアントを指定しない場合は、ロケールコードのみを使用します。
サポートされているロケールの完全なリストについては、 MongoDB Serverマニュアルの 「サポートされている言語とロケール」 を参照してください。
次のセクションでは、 MongoDBで照合を適用するさまざまな方法を示します。
コレクション
コレクションにデフォルトの照合を設定できるのは、作成時のみです。ただし、既存のコレクションの新しいインデックスで照合を指定できます。コレクションをスキャンして、デフォルトの照合を適用する、サポートされているすべての操作。詳細については、このガイドの「 インデックス 」セクションを参照してください。
次の例は、itemsという新しいコレクションを作成するときに "en_US"ロケール照合を指定する方法を示しています。
Mono.from(database.createCollection( "items", new CreateCollectionOptions().collation( Collation.builder().locale("en_US").build()))) .block();
照合が正常に作成されたかどうかを確認するには、次のように、そのコレクションのインデックスのリストを取得します。
List<Document> indexes = Flux.from(itemsCollection.listIndexes()) .collectList().block(); if (indexes != null) { indexes.forEach(idx -> System.out.println(idx.toJson())); }
上記のコードの出力には、次の内容が含まれている必要があります。
{ ... "collation": { "locale": "en_US", ... } ... }
Index
コレクションに新しいインデックスを作成する ときに、 照合 を指定できます。インデックスではドキュメントが指定された順序で保存されるため、クエリ中にメモリ内でソートする必要がありません。インデックスを使用するには、操作でインデックスで指定されているのと同じ 照合 を使用し、そのインデックスによってカバーされる必要があります。
次の例は、「name」フィールドに"en_US"ロケール照合で昇順のインデックスを作成する方法を示しています。
IndexOptions idxOptions = new IndexOptions(); idxOptions.collation(Collation.builder().locale("en_US").build()); Mono.from(itemsCollection.createIndex( Indexes.ascending("name"), idxOptions)).block();
照合が正常に作成されたかどうかを確認するには、次のように、そのコレクションのインデックスのリストを取得します。
List<Document> indexes = Flux.from(itemsCollection.listIndexes()) .collectList().block(); if (indexes != null) { indexes.forEach(idx -> System.out.println(idx.toJson())); }
上記のコードの出力には、次の内容が含まれている必要があります。
{ ... "collation": { "locale": "en_US", ... } ... }
次の例では、同じ照合を指定し、前の例で作成されたインデックスによってカバーされている操作を示しています。
FindPublisher<Document> indexPublisher = itemsCollection.find() .collation(Collation.builder().locale("en_US").build()) .sort(Sorts.ascending("name")); Flux.from(indexPublisher) .doOnNext(doc -> System.out.println(doc.toJson())) .blockLast();
操作
サポートされている操作に新しい照合を渡すことで、デフォルトの照合を上書きできます。ただし、インデックスがない場合、クエリはメモリ内ソートを実行します。これは、インデックス付き照合を使用する場合よりも遅くなります。インデックスで説明されていないソート操作の悪影響の詳細については、 MongoDB Serverマニュアルの「 インデックスを使用してクエリ結果をソートする 」を参照してください。
次の例には、次の特徴を持つクエリ操作が示されています。
参照先のコレクションには、
"en_US"コレクション セクションで指定されたものと同様の、デフォルトの 照合インデックスがあります。クエリでは、アイスランド語(
"is")の照合を指定します。これはインデックスの照合とは異なるため、クエリはインデックスを使用せず、代わりにメモリ内ソートを実行します。
FindPublisher<Document> customPublisher = itemsCollection.find() .collation(Collation.builder().locale("is").build()) .sort(Sorts.ascending("name")); Flux.from(customPublisher) .doOnNext(doc -> System.out.println(doc.toJson())) .blockLast();
照合をサポートしないインデックスの種類
ほとんどのMongoDBインデックスタイプは照合をサポートしています。ただし、次の 型はバイナリ比較のみをサポートしており、照合はサポートしていません。
Collation Options
このセクションでは、さまざまな照合オプションと、順序付けと一致の動作をさらに絞り込むための指定方法について説明します。
照合オプション | 説明 |
|---|---|
ロケール | 必須。言語とバリアントの |
バックワード | |
大文字と小文字の区別 | 大文字と小文字(大文字または小文字)を異なる値と見なすかどうかを指定します。 |
代替 | スペースと句読点を考慮するかどうかを指定します。 |
caseFirst | 大文字が最初に考慮されるか、小文字が最初に考慮されるかを指定します。 |
Max Vvariable | 空白と句読点の両方を無視するか、空白と句読点の両方を無視するかを指定します。この設定は、代替設定が「Shift」である場合にのみ有効です。 |
強度 | ICU の比較レベルを指定します。デフォルト値は「三次」です。各レベルの詳細については、 ICU の比較レベル を参照してください。 |
正規化 | 必要に応じて、テキストに対して Unicode 正規化を実行するかどうかを指定します。 Unicode 正規化の詳細については、「 Unicode 正規化形式 」を参照してください。 |
numericOrdering | 照合順序ではなく、数値に従って数値を並べ替えるかどうかを指定します。 |
前述の照合オプションの値を指定するには、Collation.Builderクラスを使用します。次の例に示すように、Collationオブジェクトを構築するには、build() メソッドを呼び出します。
Collation.builder() .caseLevel(true) .collationAlternate(CollationAlternate.SHIFTED) .collationCaseFirst(CollationCaseFirst.UPPER) .collationMaxVariable(CollationMaxVariable.SPACE) .collationStrength(CollationStrength.SECONDARY) .locale("en_US") .normalization(false) .numericOrdering(true) .build();
対応するメソッドとパラメーターの詳細については、 Collection.Builder のAPIドキュメントを参照してください。
照合の例
このセクションでは、照合をサポートするMongoDB操作の使用方法の例を取り上げます。各 の例では、次のドキュメントのコレクションから開始することを想定します。
{ "_id" : 1, "first_name" : "Klara" } { "_id" : 2, "first_name" : "Gunter" } { "_id" : 3, "first_name" : "Günter" } { "_id" : 4, "first_name" : "Jürgen" } { "_id" : 5, "first_name" : "Hannah" }
次の例では、"de@collation=phonebook" のロケールとバリアント照合を使用します。照合の "de" 部分はドイツのロケールを指定し、"collation=phonebook" 部分はバリアントを指定します。 "de"ロケール照合には、最初の文字を大文字にすることで識別される固有名を優先するためのルールが含まれています。 "collation=phonebook" バリアントでは、ulault を持つ文字は、昇順のソートで、それらの文字の前に並べ替えられます。
find() と sort() の例
次の例では、コレクションからソートされた結果を取得するときに照合を適用する方法を示しています。この操作を実行するには、例コレクションで find() を呼び出し、collation() メソッドと sort() メソッドをチェーンして、結果を受信する順序を指定します。
FindPublisher<Document> findPublisher = phonebookCollection.find() .collation(Collation.builder() .locale("de@collation=phonebook").build()) .sort(Sorts.ascending("first_name")); Flux.from(findPublisher) .doOnNext(doc -> System.out.println(doc.toJson())) .blockLast();
この操作をサンプル コレクションに対して実行すると、出力は次のようになります。
{"_id": 3, "first_name": "Günter"} {"_id": 2, "first_name": "Gunter"} {"_id": 5, "first_name": "Hannah"} {"_id": 4, "first_name": "Jürgen"} {"_id": 1, "first_name": "Klara"}
このセクションで説明されるメソッドとクラスの詳細については、次の API ドキュメントを参照してください。
findOneAndUpdate() の例
次の例では、 FindOneAndUpdateOptionsオブジェクトをインスタンス化し、それをパラメーターとして渡すことで、findOneAndUpdate()操作で照合を指定します。この例では、次の操作を実行します。
"de@collation=phonebook"照合を含む操作のオプションを設定します。値が「true」を持つ新しいフィールド「検証済み」を追加します。
更新されたドキュメントを取得して印刷します。
Document updatedDoc = Mono.from( phonebookCollection.findOneAndUpdate( Filters.lt("first_name", "Gunter"), Updates.set("verified", true), new FindOneAndUpdateOptions() .collation(Collation.builder() .locale("de@collation=phonebook") .build()) .sort(Sorts.ascending("first_name")) .returnDocument(ReturnDocument.AFTER))) .block(); if (updatedDoc != null) { System.out.println("Updated document: " + updatedDoc.toJson()); }
"Guter" は、昇順の de@collation=phonebook 照合を使用して、辞書的に "Gunter" より前にあるため、上記の操作では次のドキュメントが返されます。
Updated document: {"_id": 3, "first_name": "Günter", "verified": true}
このセクションで説明されるメソッドとクラスの詳細については、次の API ドキュメントを参照してください。
findOneAndDelete() の例
次の例では、 FindOneAndDeleteOptionsオブジェクトをインスタンス化し、それをパラメーターとして渡すことで、findOneAndDelete()操作で数値順序付け照合を指定します。コレクションには、次のドキュメントが含まれます。
{ "_id" : 1, "a" : "16 apples" } { "_id" : 2, "a" : "84 oranges" } { "_id" : 3, "a" : "179 bananas" }
照合では、数値に基づいて文字列を並べ替えるために、locale オプションを "en" に、numericOrdering オプションを "true" に設定します。
Document deletedDoc = Mono.from( numericalCollection.findOneAndDelete( Filters.gt("a", "100"), new FindOneAndDeleteOptions() .collation(Collation.builder() .locale("en") .numericOrdering(true) .build()) .sort(Sorts.ascending("a")))) .block(); if (deletedDoc != null) { System.out.println("Deleted document: " + deletedDoc.toJson()); }
上記の操作を実行すると、出力は次のようになります。
Deleted document: {"_id": 3, "a": "179 bananas"}
string "179" の数値は 100 より大きいため、前のドキュメントが唯一の一致となります。数値順序付けを行わない場合、バイナリ照合では "16"、"84"、"179" の前に "100" がソートされるため、フィルターはすべてのドキュメントと一致します。
このセクションで説明されるメソッドとクラスの詳細については、次の API ドキュメントを参照してください。
集計の例
次の例は、集計操作で照合を指定する方法を示しています。集計 を実行するには、MongoCollectionオブジェクトで aggregate() メソッドを呼び出します。
集計操作の 照合 を指定するには、集計操作によって返された AggregatePublisher で collation() メソッドを呼び出します。照合を適用するには、パイプライン内でソート集計ステージを指定します。
次の例では、例コレクションに集計パイプラインを構築し、以下を指定して照合を適用します。
Aggregates.group()を使用して各ドキュメントをfirst_nameフィールドで識別し、その値を結果の_idとして使用するグループ集計ステージ。first_nameフィールド内の一致する値のインスタンスの数を合計するためのグループ ステージのアキュムレータ。出力ドキュメントの
_idフィールドでの昇順の並べ替え。ドイツ語のロケールと、アクセントを無視する照合強度を指定する照合オブジェクト。
Bson groupStage = Aggregates.group( "$first_name", Accumulators.sum("nameCount", 1)); Bson sortStage = Aggregates.sort(Sorts.ascending("_id")); AggregatePublisher<Document> aggregatePublisher = phonebookCollection .aggregate(Arrays.asList(groupStage, sortStage)) .collation(Collation.builder() .locale("de") .collationStrength(CollationStrength.PRIMARY) .build()); Flux.from(aggregatePublisher) .doOnNext(doc -> System.out.println(doc.toJson())) .blockLast();
上記のコードでは、次のドキュメントが出力されます。
{"_id": "Gunter", "nameCount": 2} {"_id": "Hannah", "nameCount": 1} {"_id": "Jürgen", "nameCount": 1} {"_id": "Klara", "nameCount": 1}
このセクションで説明されるメソッドとクラスの詳細については、次の API ドキュメントを参照してください。