在MongoDB中按字母顺序排序文档(也称为自然排序顺序,为人类排序)

622*_*119 15 javascript natural-sort mongodb mongodb-query

我想了解如何使用MongoDB执行此操作

我的文件名称为"file1","file2","file22","file11"(名称可以是任何内容,没有特定的模式)我运行查询以获取按名称排序的所有文档,结果不是预期.

> 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" } 
Run Code Online (Sandbox Code Playgroud)

预期的是(字母/自然顺序)

{ "_id" : ObjectId("571e5a787e88d30b20b7857c"), "name" : "file1" }                                                                                            
{ "_id" : ObjectId("571e5a977e88d30b20b7857f"), "name" : "file2" }                                                                                           
{ "_id" : ObjectId("571e5a8c7e88d30b20b7857d"), "name" : "file11" }
{ "_id" : ObjectId("571e5a937e88d30b20b7857e"), "name" : "file22" }
Run Code Online (Sandbox Code Playgroud)

根据我的发现,还有其他方法可以使用aggregate+ $project和排序$meta: "textScore",但到目前为止我还没有成功.

更新:此问题的应用程序:按名称对文件夹/文件进行排序 Windows资源管理器,按名称排序的文件夹

sty*_*ane 8

MongoDB没有提供开箱即用的方法,但你仍然有两个选择:

第一种是使用该Array.prototype.sort方法对数组结果进行排序的客户端处理.

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 );
})
Run Code Online (Sandbox Code Playgroud)

我建议您做的第二个是使用一个额外的字段来规范化您的文档,该字段将"名称"中的数字保存为整数,并使用该值对文档进行排序.这意味着,您需要更新文档才能添加该字段,最好的方法是使用$set更新操作符和"批量操作"以获得最高效率.话虽这么说,从MongoDB服务器版本3.2你需要使用该collection.bulkWrite方法来实现这一目标.

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);
Run Code Online (Sandbox Code Playgroud)

MongoDB服务器版本2.6,您需要使用现已弃用的BulkAPI.

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();
Run Code Online (Sandbox Code Playgroud)

MongoDB服务器版本2.4开始,您需要一种不同的方法.

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 } } 
    );
})
Run Code Online (Sandbox Code Playgroud)

完成任何此操作后,您的文档现在如下所示:

{ "_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 }
Run Code Online (Sandbox Code Playgroud)

现在,您可以使用该.sort方法轻松地对文档进行排序.

db.mydata.find({}, { "name": 1 } ).sort( { "fileId": 1 } )
Run Code Online (Sandbox Code Playgroud)

产生以下结果:

{ "_id" : ObjectId("571e5a787e88d30b20b7857c"), "name" : "file1" }
{ "_id" : ObjectId("571e5a977e88d30b20b7857f"), "name" : "file2" }
{ "_id" : ObjectId("571e5a8c7e88d30b20b7857d"), "name" : "file11" }
{ "_id" : ObjectId("571e5a937e88d30b20b7857e"), "name" : "file22" }
Run Code Online (Sandbox Code Playgroud)