2016-04-25 15 views
15

Ich möchte herausfinden, wie diesesortieren Dokument alphabetisch (auch bekannt als natürliche Sortierreihenfolge für den Menschen Sortierung) in MongoDB

mit MongoDB zu tun, ich habe Dokumente mit Namen wie „file1“, „file2“, „file22 "," file11 "(Name kann alles sein, es gibt kein bestimmtes Muster) Ich habe die Abfrage ausgeführt, um alle Dokumente nach Namen sortiert und das Ergebnis ist nicht wie erwartet.

> db.mydata.find().sort({"name":1});                               
{ "_id" : ObjectId("571e5a787e88d30b20b7857c"), "name" : "file1" }                        
{ "_id" : ObjectId("571e5a8c7e88d30b20b7857d"), "name" : "file11" }                       
{ "_id" : ObjectId("571e5a977e88d30b20b7857f"), "name" : "file2" }                        
{ "_id" : ObjectId("571e5a937e88d30b20b7857e"), "name" : "file22" } 

Was erwartet wird, ist (alphabetisch/natürliche Ordnung)

{ "_id" : ObjectId("571e5a787e88d30b20b7857c"), "name" : "file1" }                        
{ "_id" : ObjectId("571e5a977e88d30b20b7857f"), "name" : "file2" }                       
{ "_id" : ObjectId("571e5a8c7e88d30b20b7857d"), "name" : "file11" } 
{ "_id" : ObjectId("571e5a937e88d30b20b7857e"), "name" : "file22" } 

Wie pro meiner Erkenntnis, gibt es andere Möglichkeiten, wie mit aggregate + $project und $meta: "textScore" zu sortieren, aber ich habe so nicht gelungen weit.

UPDATE: Eine Anwendung dieses Problem: Sortieren Sie die Ordner/Dateien mit Namen Windows Explorer, Folders sorted by Name

+0

nicht alle von ihnen haben 'file' in ihnen gemeinsam ?? – kryshna

+0

Nein, @ Kryshna, das ist eine vereinfachte Menge von Daten. – 6220119

+4

Ich bin mir nicht sicher, wie 'Datei1

Antwort

8

MongoDB bietet keine Möglichkeit, dies, aus der Box zu tun, aber Sie haben noch zwei Möglichkeiten:

Die erste ist eine clientseitige Verarbeitung unter Verwendung der Array.prototype.sort-Methode zum Sortieren des Array-Ergebnisses.

db.mydata.find().toArray().sort((a, b) => { 
    var x = Number(a.name.match(/\d+/g)[0]); 
    var y = Number(b.name.match(/\d+/g)[0]); 
    return x === y ? 0 :(x < y ? -1 : 1); 
}) 

Die zweiten, das ist, was ich vorschlagen, dass Sie Ihre Dokumente mit einem zusätzlichen Feld zu tun ist, normalisieren, die die Ziffern in dem „namen“ als integer und sortieren Sie Ihre Dokumente mit diesem Wert zu halten. Dies bedeutet, dass Sie Ihre Dokumente aktualisieren müssen, um dieses Feld hinzuzufügen, und die beste Möglichkeit hierfür ist die Verwendung des Aktualisierungsoperators $set und "bulk operations" für maximale Effizienz. Davon abgesehen, müssen Sie von MongoDB Server Version 3.2 die Methode collection.bulkWrite verwenden, um dies zu erreichen.

var requests = []; 

db.mydata.find({}, { "name": 1 }).forEach(doc => { 
    var fileId = Number(doc.name.match(/\d+/g)[0]); // return number from "name" value 
    requests.push({ 
     "updateOne": { 
      "filter": { "_id": doc._id }, 
      "update": { "$set": { "fileId": fileId } } 
     } 
    }); 
    // Execute per 1000 operations and re-init the requests queue 
    if(requests.length === 1000) 
     db.mydata.bulkWrite(requests); 
}) 

// Clean up queues 
if (requests.length > 0) 
    db.mydata.bulkWrite(requests); 

Von MongoDB-Server Version 2.6 müssen Sie das jetzt veraltet Bulk API verwenden.

var bulk = db.mydata.initializeUnorderedBulkOp(); 
var count = 0; 

db.collection.find({}, { "name": 1 }).forEach(function(doc) { 
    var fileId = Number(doc.name.match(/\d+/g)[0]); 
    bulk.find({"_id": doc._id}).updateOne({ 
     "$set": { "fileId": fileId } 
    }); 
    count++; 
    if (count % 1000 === 0) { 
     bulk.execute(); 
     bulk = db.mydata.initializeUnorderedBulkOp(); 
    } 
}) 

if (count > 0) 
    bulk.execute(); 

Von MongoDB-Server Version 2.4 ab benötigen Sie einen anderen Ansatz.

db.collection.find({}, { "name": 1 }).forEach(function(doc) { 
    var fileId = Number(doc.name.match(/\d+/g)[0]); 
    db.collection.update(
     { "_id": doc._id }, 
     {"$set": { "fileId": fileId } } 
    ); 
}) 

Nach jeder dieser Operation sehen Ihre Dokumente nun wie folgt aus:

{ "_id" : ObjectId("571e5a787e88d30b20b7857c"), "name" : "file1", "fileId" : 1 } 
{ "_id" : ObjectId("571e5a8c7e88d30b20b7857d"), "name" : "file11", "fileId" : 11 } 
{ "_id" : ObjectId("571e5a977e88d30b20b7857f"), "name" : "file2", "fileId" : 2 } 
{ "_id" : ObjectId("571e5a937e88d30b20b7857e"), "name" : "file22", "fileId" : 22 } 

Jetzt können Sie ganz einfach sortieren Sie Ihre Dokumente, die die .sort Methode.

db.mydata.find({}, { "name": 1 }).sort({ "fileId": 1 }) 

das folgende Ergebnis erzeugt:

{ "_id" : ObjectId("571e5a787e88d30b20b7857c"), "name" : "file1" } 
{ "_id" : ObjectId("571e5a977e88d30b20b7857f"), "name" : "file2" } 
{ "_id" : ObjectId("571e5a8c7e88d30b20b7857d"), "name" : "file11" } 
{ "_id" : ObjectId("571e5a937e88d30b20b7857e"), "name" : "file22" } 
+0

Es ist nett, mehr über Bulk-Update-Operationen zu verstehen. Die Einführung von zusätzlichen Feldern ist der Weg, wenn wir das Muster des sortierten Wertes herausfinden können. In diesem Fall kann der Wert jedoch nichts anderes sein als normale Strings, IP-Adresse, ... Über den clientseitigen Ansatz wird es ein Problem sein, wenn wir Paginierung durchführen. Wenn Sie nicht alle Daten an die Clientseite zurückgeben können (was zu einem Leistungsproblem führen kann), führt diese Vorgehensweise nicht zum erwarteten Ergebnis. – 6220119

+0

@ 6220119 Wie ich schon sagte Normalisierung ist definitiv der Weg zu gehen, weil die clientseitige Operation zu einem Leistungsabfall in der Anwendung führen wird. Auch das Finden eines Musters sollte ein Problem sein, da der "Name" einen Wert desselben Typs enthält.Mit der normalen Zeichenkette können Sie beispielsweise Dokumente nach der Länge der Zeichenkette in aufsteigender Reihenfolge und dann alphabetisch sortieren, was bedeutet, dass Ihr zusätzliches Feld die Länge hat. Aber das ist definitiv die Lösung für Ihr Problem. – styvane

+0

Sortierung nach Länge und dann alphabetisch ergeben nicht das richtige Ergebnis. Weitere Informationen finden Sie unter http://imgur.com/wPR39Mw. Und aussehen wie das ist eine andere Frage geworden? Wie benutzt man mongoDB um String-Werte für performante Sortieroperationen zu speichern? – 6220119