本篇将会介绍 MongoDB 中的游标 sort() 方法,实现查询结果的排序功能。
sort() 方法
sort() 方法可以为查询返回的文档指定指定一个显示顺序:
cursor.sort({field1: order, field2: order, ...})
sort() 方法支持多字段排序,每个字段都可以指定升序或者降序排序。
{ field: 1 } 表示按照字段的升序排序:
cursor.sort({ field: 1 })
{ field: -1} 表示按照字段的降序排序:
cursor.sort({field: -1})
下面的语法表示先按照字段 field1 的升序排序,然后再按照字段 field2 的降序排序:
cursor.sort({field1: 1, field2: -1});
相同类型的数据比较很简单,但是不同 BSON 类型的数据比较略微有些复杂。
MongoDB 使用以下从小到大的顺序比较不同的 BSON 类型:
- MinKey(内部类型)
- 空类型
- 数字(整数、长整数、双精度浮点数、十进制数字)
- 符号、字符串
- 对象
- 数组
- BinData
- ObjectId
- 布尔类型
- 日期
- 时间戳
- 正则表达式
- MaxKey(内部类型)
更多详细信息可以参考官方文档。
sort() 示例
接下来我们将会使用以下 products 集合演示 sort() 方法的使用。
db.products.insertMany([
{ "_id" : 1, "name" : "xPhone", "price" : 799, "releaseDate" : ISODate("2011-05-14T00:00:00Z"), "spec" : { "ram" : 4, "screen" : 6.5, "cpu" : 2.66 }, "color" : [ "white", "black" ], "storage" : [ 64, 128, 256 ] },
{ "_id" : 2, "name" : "xTablet", "price" : 899, "releaseDate" : ISODate("2011-09-01T00:00:00Z"), "spec" : { "ram" : 16, "screen" : 9.5, "cpu" : 3.66 }, "color" : [ "white", "black", "purple" ], "storage" : [ 128, 256, 512 ] },
{ "_id" : 3, "name" : "SmartTablet", "price" : 899, "releaseDate" : ISODate("2015-01-14T00:00:00Z"), "spec" : { "ram" : 12, "screen" : 9.7, "cpu" : 3.66 }, "color" : [ "blue" ], "storage" : [ 16, 64, 128 ] },
{ "_id" : 4, "name" : "SmartPad", "price" : 699, "releaseDate" : ISODate("2020-05-14T00:00:00Z"), "spec" : { "ram" : 8, "screen" : 9.7, "cpu" : 1.66 }, "color" : [ "white", "orange", "gold", "gray" ], "storage" : [ 128, 256, 1024 ] },
{ "_id" : 5, "name" : "SmartPhone", "price" : 599, "releaseDate" : ISODate("2022-09-14T00:00:00Z"), "spec" : { "ram" : 4, "screen" : 9.7, "cpu" : 1.66 }, "color" : [ "white", "orange", "gold", "gray" ], "storage" : [ 128, 256 ] },
{ "_id" : 6, "name" : "xWidget", "spec" : { "ram" : 64, "screen" : 9.7, "cpu" : 3.66 }, "color" : [ "black" ], "storage" : [ 1024 ] },
{ "_id" : 7, "name" : "xReader", "price" : null, "spec" : { "ram" : 64, "screen" : 6.7, "cpu" : 3.66 }, "color" : [ "black", "white" ], "storage" : [ 128 ] }
])
示例一:单个字段排序
下面的查询返回了所有存在 price 字段的文档,返回的字段包含 _id、name 以及 price:
db.products.find({
'price': {
$exists: 1
}
}, {
name: 1,
price: 1
})
输出结果如下:
[
{ _id: 1, name: 'xPhone', price: 799 },
{ _id: 2, name: 'xTablet', price: 899 },
{ _id: 3, name: 'SmartTablet', price: 899 },
{ _id: 4, name: 'SmartPad', price: 699 },
{ _id: 5, name: 'SmartPhone', price: 599 },
{ _id: 7, name: 'xReader', price: null }
]
如果想要按照价格从低到高对返回的结果进行排序,可以使用以下 sort() 方法:
db.products.find({
'price': {
$exists: 1
}
}, {
name: 1,
price: 1
}).sort({
price: 1
})
输出结果如下:
[
{ _id: 7, name: 'xReader', price: null },
{ _id: 5, name: 'SmartPhone', price: 599 },
{ _id: 4, name: 'SmartPad', price: 699 },
{ _id: 1, name: 'xPhone', price: 799 },
{ _id: 2, name: 'xTablet', price: 899 },
{ _id: 3, name: 'SmartTablet', price: 899 }
]
以上示例中,价格为空的产品排在最前面,然后依次从低到高进行排列。
如果想要按照价格从高到低进行排序,可以将 sort() 方法中的 price 字段设置为 -1:
db.products.find({
'price': {
$exists: 1
}
}, {
name: 1,
price: 1
}).sort({
price: -1
})
返回结果如下:
[
{ _id: 2, name: 'xTablet', price: 899 },
{ _id: 3, name: 'SmartTablet', price: 899 },
{ _id: 1, name: 'xPhone', price: 799 },
{ _id: 4, name: 'SmartPad', price: 699 },
{ _id: 5, name: 'SmartPhone', price: 599 },
{ _id: 7, name: 'xReader', price: null }
]
示例二:多个字段排序
以下示例使用 sort() 方法按照 name 和 price 字段从小到大的顺序对查询结果进行排序:
db.products.find({
'price': {
$exists: 1
}
}, {
name: 1,
price: 1
}).sort({
price: 1,
name: 1
});
输出结果如下:
[
{ _id: 7, name: 'xReader', price: null },
{ _id: 5, name: 'SmartPhone', price: 599 },
{ _id: 4, name: 'SmartPad', price: 699 },
{ _id: 1, name: 'xPhone', price: 799 },
{ _id: 3, name: 'SmartTablet', price: 899 },
{ _id: 2, name: 'xTablet', price: 899 }
]
在以上示例中,sort() 方法首先按照价格进行排序,然后对价格相同的结果再按照名称进行排序。_id 为 3 和 2 的产品价格相同,都是 899;它们按照名称进行升序排列,SmartTablet 排在了 xTablet 之前。
以下示例按照价格升序、名称降序的方式对返回的产品进行排序:
db.products.find({
'price': {
$exists: 1
}
}, {
name: 1,
price: 1
}).sort({
price: 1,
name: -1
})
Code language: PHP (php)
Output:
[
{ _id: 7, name: 'xReader', price: null },
{ _id: 5, name: 'SmartPhone', price: 599 },
{ _id: 4, name: 'SmartPad', price: 699 },
{ _id: 1, name: 'xPhone', price: 799 },
{ _id: 2, name: 'xTablet', price: 899 },
{ _id: 3, name: 'SmartTablet', price: 899 }
]
此时,xTable 排在了 SmartTablet 之前。
示例三:基于日期排序
以下示例按照日期字段 releaseDate 对 products 集合中的文档进行排序,查询只返回了存在 releaseDate 字段的文档,并且只返回了 _id、name 以及 releaseDate 字段:
db.products.find({
releaseDate: {
$exists: 1
}
}, {
name: 1,
releaseDate: 1
}).sort({
releaseDate: 1
});
查询返回的结果如下:
[
{
_id: 1,
name: 'xPhone',
releaseDate: ISODate("2011-05-14T00:00:00.000Z")
},
{
_id: 2,
name: 'xTablet',
releaseDate: ISODate("2011-09-01T00:00:00.000Z")
},
{
_id: 3,
name: 'SmartTablet',
releaseDate: ISODate("2015-01-14T00:00:00.000Z")
},
{
_id: 4,
name: 'SmartPad',
releaseDate: ISODate("2020-05-14T00:00:00.000Z")
},
{
_id: 5,
name: 'SmartPhone',
releaseDate: ISODate("2022-09-14T00:00:00.000Z")
}
]
示例四:基于嵌入字段排序
以下示例使用嵌入式文档 spec 中的 ram 字段对产品进行排序:
db.products.find({}, {
name: 1,
spec: 1
}).sort({
"spec.ram": 1
});
输出结果如下:
[
{ _id: 1, name: 'xPhone', spec: { ram: 4, screen: 6.5, cpu: 2.66 } },
{
_id: 5,
name: 'SmartPhone',
spec: { ram: 4, screen: 9.7, cpu: 1.66 }
},
{
_id: 4,
name: 'SmartPad',
spec: { ram: 8, screen: 9.7, cpu: 1.66 }
},
{
_id: 3,
name: 'SmartTablet',
spec: { ram: 12, screen: 9.7, cpu: 3.66 }
},
{
_id: 2,
name: 'xTablet',
spec: { ram: 16, screen: 9.5, cpu: 3.66 }
},
{
_id: 6,
name: 'xWidget',
spec: { ram: 64, screen: 9.7, cpu: 3.66 }
},
{
_id: 7,
name: 'xReader',
spec: { ram: 64, screen: 6.7, cpu: 3.66 }
}
]