2012-09-19 21 views
7

Mit einer Sammlung:Sortieren nach Sortierung in MongoDB

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

ab. Wie sortiere ich es in Spanisch case insensitive?

Ich habe dies versucht:

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}); 

Ausgabe lautet:

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

gewünschte Ergebnis:

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

Antwort

10

Ich weiß, das ein alter Thread, aber ich denke, es ist sowieso zu beantworten nützlich wäre.

Sie möchten auf keinen Fall die Sortierung in Ihrer App durchführen, da Sie alle Dokumente in der Sammlung in den Speicher holen müssen, um sie zu sortieren und das gewünschte Fenster zurückzugeben. Wenn Ihre Sammlung riesig ist, ist dies äußerst ineffizient. Die Datenbank sollte die Sortierung durchführen und das Fenster an Sie zurücksenden.

MongoDB unterstützt jedoch keine länderspezifische Sortierung, sagen Sie. Wie löst man das Problem? Die Magie ist das Konzept der "Sortierschlüssel".

Nehmen wir an, Sie hatten das normale englische/lateinische Alphabet von "a" bis "z". Sie erstellen eine Sortierschlüsselzuordnung von "a" zu "01" und von "b" zu "02" usw. bis "z" bis "26". Das heißt, ordnen Sie jedem Buchstaben eine Nummer in der Sortierreihenfolge für diese Sprache zu und codieren Sie diese Nummer dann als Zeichenfolge. Ordnen Sie dann die Zeichenfolge, die Sie sortieren möchten, dieser Art von Sortierschlüssel zu. Zum Beispiel würde "abc" zu "010203" werden. Dann fügen Sie eine Eigenschaft eine Eigenschaft zu Ihrem Dokument mit dem Sortierschlüssel, und fügen Sie den Namen der Eigenschaft mit dem Namen des Gebietsschemas:

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

Jetzt können Sie in der Sprache sortieren „en“ nur durch Indizierung Verwenden Sie in der Eigenschaft "name_en" die einfache englische MongoDB-Sortierung für Selektoren und Bereiche anstelle der Eigenschaft "name".

Jetzt haben Sie eine andere verrückte Sprache "xx", wo die Reihenfolge des Alphabets "acb" statt "abc" ist.(Ja, es gibt Sprachen, die Verwirrung mit der Ordnung des lateinischen Alphabets in dieser Art und Weise!) Die Sortierschlüssel so sein würden:

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

nun alles, was Sie tun müssen, ist erstellen Indizes auf name_en und name_xx und Verwenden Sie die reguläre MongoDB-Sortierung, um diese Gebietsschemas korrekt zu sortieren. Grundsätzlich sind die zusätzlichen Eigenschaften Proxies zum Sortieren in verschiedenen Gebietsschemas.

Woher bekommen Sie diese Mappings, fragen Sie? Sie sind ja kein Globalisierungsexperte, oder?

Nun, wenn Sie Java, C oder C++ verwenden, gibt es fertige Klassen, die diese Zuordnung für Sie übernehmen. Verwenden Sie in Java die Standard-Collator-Klasse oder verwenden Sie die icu4j-Collator-Klasse. Wenn Sie C/C++ verwenden, verwenden Sie die C/C++ - Version der ICU Collator-Funktionen/-Klasse. Für andere Sprachen sind Sie eine Art Pech, es sei denn, Sie können eine Bibliothek finden, die das bereits tut.

Hier sind einige Links, die Sie sie finden helfen:

Die Standard-Java-Bibliothek Sorter: http://docs.oracle.com/javase/7/docs/api/java/text/Collator.html#getCollationKey(java.lang.String)

Die C++ Collator Klasse: http://icu-project.org/apiref/icu4c/classicu_1_1Collator.html#ae0bc68d37c4a88d1cb731adaa5a85e95

Sie können auch verschiedene Sortierschlüssel machen, die es Ihnen ermöglichen, Sortierung ohne Berücksichtigung der Groß-/Kleinschreibung für jedes Gebietsschema (ja, das Fallmapping ist für das Gebietsschema empfindlich!) und akzentunabhängig, Unicode-Variantenunempfindlich oder eine beliebige Kombination der obigen. Das einzige Problem ist, dass Sie jetzt viele Eigenschaften haben, die jede sortierbare Eigenschaft parallelisieren, und Sie müssen sie alle synchron halten, wenn Sie die Eigenschaft "name" der Basis aktualisieren. Es ist ein Schmerz in der Sie-wissen-was, aber immer noch, es ist besser als das Sortieren in Ihrer App oder Business-Logik-Ebene.

Achten Sie auch auf Cursor mit Bereichen. Im Englischen ignorieren wir zum Beispiel Akzente auf Zeichen. Ein "Ö" sortiert also genauso wie "O" und es erscheint im Bereich "M" bis "Z". Aber auf Schwedisch sortieren Buchstaben mit Akzenten nach "Z". Also, wenn Sie einen Bereich "M" - "Z" machen, werden Sie eine Reihe von Datensätzen beginnend mit "Ö" einschließen, die in Englisch, aber nicht in Schwedisch sein sollten.

Dies hat auch Auswirkungen auf das Sharding, wenn Sie eine Texteigenschaft eines Dokuments teilen. Sei vorsichtig, welche Bereiche in welchen Shard gehören. Es wäre besser, Dinge zu zerstückeln, die nicht lokalitätsempfindlich sind, wie Hashes.

+0

Würden Sie also in diesem Beispiel nach 5 oder 6 Zeichen aufhören und auf kürzere Wörter 0-füllen? – Stephane

+0

Nein, eine kürzere Zeichenfolge "gewinnt" immer den Vergleich. "abc" sortiert vor "abcdef", obwohl sie das gleiche Präfix haben, daher sollte "010203" vor "010203040506" sortieren. Die Sortierschlüsseleigenschaften sollten als Zeichenfolgen und nicht als Zahlen verglichen werden. –

+0

Oh, und die Sortierschlüssel, die die Java- und C++ - Collatoren zurückgeben, sehen sehr anders aus als die Beispiele, die ich hier gegeben habe. Ich habe einfach "01", "02" usw. benutzt, weil sie einfach zu verstehen waren. In Java beispielsweise gibt die Methode getCollationKey() ein Array von Ganzzahlen zurück, das die Bit-gepackten Sortierelemente enthält. Ich würde vorschlagen, dieses Array in eine Folge von Hexadezimalziffern umzuwandeln, so dass MongoDB sie als Strings mit den englischen Standardvergleichsregeln vergleichen kann, die auf Hex funktionieren. –

1

Leider können Sie keine Groß- und Kleinschreibung Art noch tun, nicht wahr Die Sortierung erfolgt nun in der Reihenfolge "index". Es ist ein offenes Ticket:

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

Sie betrachten könnte die Art in Mongo Skipping, und es in Ihrer Anwendung zu tun.

3

Momentan implementiert MongoDB keine Sortierung.

Die Implementierung der Unicode collation standard ist der beste Weg, um das zu lösen.

Dies würde jedoch die Sortierung verlangsamen und Indizes größer machen. Also, jetzt ist es am besten, in Ihrer Anwendung zu sortieren.

2

Eine einfache Lösung besteht darin, ein neues Feld zu erstellen, in dem Text in einfache ASCII-Zeichen konvertiert wird.

{ "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?" } 

Dann einfach sortieren nach ‚name_sort‘

+0

So etwas würde funktionieren. Das Sortieren in der App ist, wie von anderen vorgeschlagen, keine praktikable Alternative, wenn Sie Millionen von Zeilen haben. Daher muss ein sortierbares Feld für einen echten Workaround erstellt werden. –

8

Obwohl die anderen Antworten hier für die MongoDB-Versionen 3.2.x und vorherige, ab 3.4.0, korrekt sind, können Sie "Kollatierungen für eine Sammlung oder eine Ansicht, einen Index oder bestimmte Operationen, die Kollatierung unterstützen" angeben.

Full documentation for the feature is here.

+0

Das wäre jetzt die richtige Antwort. Da MongoDB das Definieren von Sortierungen beim Erstellen von Sammlungen oder beim Erstellen von Ansichten mit der gewünschten Sortierung ermöglicht. Sehen Sie sich das bitte an: https://docs.mongodb.com/manual/reference/method/db.createCollection/#createcollection-collation-example –

+0

Ich würde MongoDB definitiv aufgeben, da ich dachte, dass es keinen einfachen Weg gibt um es mit meiner Muttersprache, die Portugiesisch (aus Brasilien) ist, zu verwenden. Aber das scheint eine sehr gute Lösung zu sein. –

Verwandte Themen