8

コレクションを持つ:

{"name": "a"},
{"name": "B"},    
{"name": "b"},    
{"name": "c"},    
{"name": "á"},    
{"name": "A"}

元。スペイン語の大文字と小文字を区別しないで並べ替えるには?

私はこれを試しました:

var abc = [{"name": "a"}, {"name": "B"}, {"name": "b"}, {"name": "c"}, {"name": "á"}, {"name": "A"}];
for (i in abc) db.abc.save(abc[i]);

db.abc.find({},{"_id":0}).sort({"name":1});

出力は次のとおりです。

[
    { "name" : "A" },
    { "name" : "B" },
    { "name" : "a" },
    { "name" : "b" },
    { "name" : "c" },
    { "name" : "á" },
]

望ましい結果:

[
    { "name" : "a" },
    { "name" : "á" },
    { "name" : "A" },
    { "name" : "b" },
    { "name" : "B" },
    { "name" : "c" }
]
4

5 に答える 5

10

これが古いスレッドであることは知っていますが、とにかく答えると役立つと思います。

コレクション内のすべてのドキュメントをメモリに格納して並べ替え、必要なウィンドウを返す必要があるため、アプリで並べ替えを実行したくないことは間違いありません。コレクションが膨大な場合、これは非常に非効率的です。データベースはソートを行い、ウィンドウを返します。

しかし、MongoDB はロケールに依存した並べ替えをサポートしていません。問題をどのように解決しますか?魔法は「ソートキー」の概念です。

基本的に、「a」から「z」までの通常の英語/ラテン語のアルファベットがあるとしましょう。あなたがすることは、「a」から「01」、「b」から「02」など、「z」から「26」までのソートキーマッピングを作成することです。つまり、その言語のソート順ですべての文字を数値にマップし、その数値を文字列としてエンコードします。次に、並べ替える文字列をこの種類の並べ替えキーにマップします。たとえば、「abc」は「010203」になります。次に、プロパティの並べ替えキーを使用してドキュメントにプロパティを追加し、プロパティの名前をロケールの名前に追加します。

{
    name: "abc",
    name_en: "010203"
}

プロパティ「name_en」にインデックスを付けるだけで言語「en」でソートし、「name」プロパティの代わりにセレクターと範囲にプレーンな古い英語ベースの MongoDB ソートを使用できるようになりました。

ここで、アルファベットの順序が「abc」ではなく「acb」である別のクレイジーな言語「xx」があるとします。(はい、そのようにラテン アルファベットの順序を台無しにする言語があります!) ソート キーは次のようになります。

{
    name: "abc",
    name_en: "010203",
    name_xx: "010302"
}

あとは、name_en と name_xx にインデックスを作成し、通常の MongoDB ソートを使用して、これらのロケールで正しくソートするだけです。基本的に、追加のプロパティは、異なるロケールでソートするためのプロキシです。

では、これらのマッピングはどこで取得するのでしょうか? 結局のところ、あなたはグローバリゼーションの専門家ではありませんよね?

Java、C、または C++ を使用している場合は、このマッピングを行う既製のクラスがあります。Java では、標準の Collat​​or クラスを使用するか、icu4j Collat​​or クラスを使用します。C/C++ を使用している場合は、C/C++ バージョンの ICU Collat​​or 関数/クラスを使用してください。他の言語の場合、すでにそれを行うライブラリが見つからない限り、運が悪いです。

それらを見つけるのに役立ついくつかのリンクを次に示します。

標準 Java ライブラリ Collat​​or: http://docs.oracle.com/javase/7/docs/api/java/text/Collat​​or.html#getCollat​​ionKey(java.lang.String)

C++ コレーター クラス: http://icu-project.org/apiref/icu4c/classicu_1_1Collat ​​or.html#ae0bc68d37c4a88d1cb731adaa5a85e95

また、ロケールごとに大文字と小文字を区別せずに並べ替えることができる別の並べ替えキーを作成することもできます (はい、大文字と小文字のマッピングはロケールを区別します!)、アクセントを区別せず、Unicode バリアントを区別しない、または上記の任意の組み合わせを使用できます。唯一の問題は、ソート可能な各プロパティに対応する多くのプロパティがあり、基本の「名前」プロパティを更新するときにそれらすべてを同期させなければならないことです。知っていることは面倒ですが、それでも、アプリやビジネス ロジック レイヤーで並べ替えを行うよりはましです。

範囲を持つカーソルにも注意してください。たとえば、英語では、文字のアクセントを無視します。したがって、「Ö」は「O」と同じ方法でソートされ、「M」から「Z」の範囲に表示されます。ただし、スウェーデン語では、アクセント付きの文字は "Z" の後に並べ替えられます。したがって、「M」から「Z」までの範囲を指定すると、「Ö」で始まる一連のレコードが含まれます。これらのレコードは、英語では存在するはずですが、スウェーデン語では存在しないはずです。

これは、ドキュメントのテキスト プロパティで分割する場合、シャーディングにも影響します。どの範囲がどのシャードに入るのかに注意してください。ハッシュのように、ロケールに依存しないものを分割する方がよいでしょう。

于 2014-06-04T05:55:45.850 に答える
3

現在、MongoDB は照合を実装していません。

これを解決するには、 Unicode 照合基準を実装するのが最善の方法です。

ただし、これによりソートが遅くなり、インデックスが大きくなります。したがって、今のところ、アプリケーションでソートするのが最善です。

于 2012-09-19T15:52:49.267 に答える
2

簡単な回避策は、プレーンな ASCII 文字に変換されたテキストで新しいフィールドを作成することです。

{ "name": "Ánfora", "name_sort": "anfora" }
{ "name": "Óscar", "name_sort": "oscar" }
{ "name": "Barça", "name_sort": "barc~a" }
{ "name": "Niño", "name_sort": "nin~o" }
{ "name": "¡Hola!", "name_sort": "hola!" }
{ "name": "¿qué?", "name_sort": "que?" }

次に、「name_sort」で並べ替えるだけです

于 2013-08-01T20:12:40.493 に答える
1

残念ながら、大文字と小文字を区別しない並べ替えはまだ実行できません。現在、並べ替えは「インデックス」順で返されます。オープンチケットがあります:

https://jira.mongodb.org/browse/SERVER-90

mongo で並べ替えをスキップして、アプリで実行することを検討してください。

于 2012-09-19T15:47:47.327 に答える