MongoDB在排序时首先返回大写字符串。

8

当我尝试对一个集合的字符串字段(这里是Title)进行排序时,排序结果并不如预期。请看下面:

db.SomeCollection.find().limit(50).sort({ "Title" : -1 });

实际结果排序

  • "Title" : "geog.3 学生用书"
  • "Title" : "geog.2 学生用书"
  • "Title" : "geog.1 学生用书"
  • "Title" : "Zoe 和 Swift"
  • "Title" : "Zip 在主题公园"
  • "Title" : "Zip 在超市"

期望结果排序

  • "Title" : "Zoe 和 Swift"
  • "Title" : "Zip 在主题公园"
  • "Title" : "Zip 在超市"
  • "Title" : "geog.3 学生用书"
  • "Title" : "geog.2 学生用书"
  • "Title" : "geog.1 学生用书"

当我尝试按日期字段排序时,出现了同样的问题。

有什么建议吗?


如果日期没有正确排序,我会怀疑是因为您的日期表示方式不可排序。 - WiredPrairie
5个回答

6
更新: 版本3.4支持大小写不敏感索引 这是已知的问题。MongoDB不支持字符串的词法排序(JIRA: 字符串词法排序)。您应该在应用程序代码中对结果进行排序,或使用数字字段进行排序。但它可以可靠地按日期字段排序。您能否举一个排序日期字段无效的例子?

5
如果你有一百万条记录并且想对它们进行排序并返回前十条记录,这是不可行的。 - cdmckay

3

您到底感到惊讶的是什么?

它基于符号的数字表示的呈现进行排序。如果您在这里查看(我知道mongodb将字符串存储为UTF-8,因此这仅用于教育目的),您将看到大写字母具有比小写字母更低的相应数字。因此,它们将排在前面。

Mongodb无法根据本地化或大小写不敏感来排序字母。

在您的情况下,g的数字比Z更高,因此它首先出现(按降序排序)。然后3的相应数字高于21。因此基本上一切都正确。


3
如果您使用聚合操作,可以看到以下预期输出:
db.collection.aggregate([
{ 
    "$project": {
       "Title": 1,        
       "output": { "$toLower": "$Title" }       
    }},
    { "$sort": {  "output":-1 } },
    {"$project": {"Title": 1, "_id":0}}
])

它将会给出以下预期输出
{
    "result" : [ 
        {
            "Title" : "Zoe and Swift"
        }, 
        {
            "Title" : "Zip at the Theme Park"
        }, 
        {
            "Title" : "Zip at the Supermarket"
        }, 
        {
            "Title" : "geog.3 students' book"
        }, 
        {
            "Title" : "geog.2 students' book"
        }, 
        {
            "Title" : "geog.1 students' book"
        }
    ],
    "ok" : 1
}


2

从日期无法正确排序开始...

如果您将日期存储为字符串,则需要将其作为字符串进行排序。这很简单:

2013-11-08  // yyyy-mm-dd (the dashes would be optional)

只要每个日期字符串的每一部分都正确地填充了0,这些字符串就会自然排序,并且按照你的预期方式排序。
完整的日期时间通常存储在UTC中:
2013-11-23T10:46:01.914Z

但是,我建议您考虑使用原生的 MongoDB Date 而不是将日期值存储为字符串,这样可能更有意义 (参考文献)。如果您查看MongoDb的聚合框架,您会发现有许多函数可以操作这些日期,而字符串的功能非常有限。

至于字符串排序,有人指出它是按计算机存储数据的方式进行排序,而不是像人类排序的方式。如果您考虑字符串存储为其 ASCII/UTF-8 表示形式,您应该能够看到为什么排序是按照它的方式工作的:

Zoe = [90, 111, 101]
geo = [103, 101, 111]

如果按照您指定的顺序进行排序,您将看到"geo"的内部字节表示大于字符串"Zoe"(在这种情况下,10390更高)。
通常,在使用MongoDb时,建议如果需要对大小写混合的字符串进行排序,则将字符串存储两次:
1. 原始字符串("Title") 2. 作为标准化字符串。例如,全部转换为“小写”,可能还将重音字符转换为公共字符。因此,您最终会得到一个名为"SortedTitle"的新字段,并且您的代码将使用该字段进行排序,但向用户显示实际的"Title"

0
如果您正在使用ror和mongomapper,则按照以下步骤操作:
我已经取了我的模型名称abc,并获取了标题的结果。
@test_abc_details_array_full=Abc.collection.aggregate([

     {"$project"=> {
       "Title"=> 1,        
       "output"=> { "$toLower"=> "$Title" }       
    }},
    { "$sort"=> {  "output"=>1 } },        
    {"$project"=> {Title: 1, _id:0}},

  ]); 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接