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

时间:2013-11-08 09:05:10

标签: mongodb sorting

当我尝试对字符串字段(此处为Title)进行排序时,排序不按预期工作。请参阅以下内容:

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

实际结果订单

  • “标题”:“geog.3学生书”
  • “标题”:“geog.2学生书”
  • “标题”:“geog.1学生书”
  • “Title”:“Zoe and Swift”
  • “标题”:“在主题公园拉链”
  • “标题”:“超市拉链”

预期结果订单

  • “Title”:“Zoe and Swift”
  • “标题”:“在主题公园拉链”
  • “标题”:“超市拉链”
  • “标题”:“geog.3学生书”
  • “标题”:“geog.2学生书”
  • “标题”:“geog.1学生书”

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

有什么建议吗?

5 个答案:

答案 0 :(得分:6)

更新:版本3.4有case insensitive indexes

这是一个已知问题。 MongoDB不支持字符串的词法排序(JIRA: String lexicographical ordering)。您应该在应用程序代码中对结果进行排序,或使用数字字段进行排序。它应该可靠地排序日期字段。你能举例说明按日期排序不起作用吗?

答案 1 :(得分:3)

你究竟有什么惊喜?

它根据符号数字表示的表示进行排序。如果你看here(我知道mongodb以UTF-8存储字符串,所以这仅用于教育目的)。您将看到大写字母的对应数字低于小写字母。因此他们将走在前面。

Mongodb无法根据本地化或不区分大小写对字母进行排序。

在你的情况下,g的数字比Z高,所以它先行(按递减顺序排序)。然后3的相应数字高于21。基本上一切都是正确的。

答案 2 :(得分: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
    }

答案 3 :(得分:2)

从没有正确排序的日期开始......

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

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

只要日期字符串的每一段都正确填充0,字符串就会按照您期望的方式自然排序。

完整日期时间通常以UTC格式存储:

2013-11-23T10:46:01.914Z

但是,我还建议您不要将日期值存储为字符串,而是考虑使用本机MongoDB Date是否更有意义(reference)。如果你看一下MongoDb的聚合框架,你会发现有很多functions可以操作这些日期,而字符串非常有限。

关于字符串排序,有人指出它像计算机那样排序存储数据而不是你作为一个人排序的方式。如果您认为字符串存储为ASCII / UTF-8表示,您应该看到为什么排序工作原理:

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

如果您按照指定的顺序按降序对它们进行排序,您应该看到"geo"的内部字节表示大于字符串"Zoe"的方式(103在这种情况下,排序高于90

通常,使用MongoDb时的建议是,如果需要对具有混合大小写的字符串进行排序,则将字符串存储两次:

  1. 原始字符串("Title"
  2. 作为规范化字符串。可能例如全部为“小写”,可能带有重音字符也转换为普通字符。因此,您最终会得到一个名为"SortedTitle"的新字段,您的代码会使用该字段进行排序,但会向用户显示实际的“Title"

答案 4 :(得分:0)

如果您正在使用ror和mongomapper,请按照以下步骤操作:

我已经取了我的模型名称abc并获取Title的结果。

@test_abc_details_array_full=Abc.collection.aggregate([

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

  ]);