分享到

简介

对于大多数数据库系统而言,对显示或检索的数据进行排序是一项关键操作,它有助于将数据库系统与其他数据存储机制区分开来。能够独立于存储的序号来操作各种字段的排序、优先级和解释,是数据库本身及其相关查询系统最有用的功能之一。

MongoDB 提供了多种方法来控制从查询返回数据时的排序方式。在本指南中,我们将介绍如何根据您的用例以各种方式对数据进行排序。我们将介绍简单排序和复合排序、如何更改排序顺序以及如何在与其他运算符结合使用时应用排序。

设置示例数据

为了演示排序的工作原理,我们将查询包含在 students 集合 中的多个文档。您可以通过复制并粘贴以下内容来创建 students 集合并插入我们将要查询的文档

db.students.insertMany([
{
first_name: 'Carol',
last_name: 'Apple',
dob: ISODate('2010-10-30'),
address: {
street: {
name: 'Flint Rd.',
number: '803',
},
city: 'Camden',
zip: '10832',
},
},
{
first_name: 'Spencer',
last_name: 'Burton',
dob: ISODate('2008-12-04'),
address: {
street: {
name: 'Edgecombe St.',
number: '2083b',
},
city: 'Zoofreid',
zip: '80828',
},
},
{
first_name: 'Nixie',
last_name: 'Languin',
dob: ISODate('2011-02-11'),
address: {
street: {
name: 'Kensington Ln.',
number: '33',
},
city: 'Zoofreid',
zip: '80829',
},
},
{
first_name: 'Anthony',
last_name: 'Apple',
dob: ISODate('2009-08-16'),
address: {
street: {
name: 'Flint Rd.',
number: '803',
},
city: 'Camden',
zip: '10832',
},
},
{
first_name: 'Rose',
last_name: 'Southby',
dob: ISODate('2011-03-03'),
address: {
street: {
name: 'Plainfield Dr.',
number: '4c',
},
city: 'Nambles',
zip: '38008',
},
},
{
first_name: 'Lain',
last_name: 'Singh',
dob: ISODate('2013-06-22'),
address: {
street: {
name: 'Plainfield Dr.',
number: '308',
},
city: 'Brighton',
zip: '18002',
},
},
])

插入上述文档后,继续下一节以了解简单排序。

如何对单个字段进行排序

在 MongoDB 中对结果进行排序的基本方法是将 .sort() 方法附加到查询中。.sort() 方法接受一个文档作为参数,该文档指定要排序的字段以及排序方向。

最基本的排序结果方法是提供一个文档,该文档指定一个字段,指示列名,其值为 1,表示升序排序

请注意,我们提供了 MongoDB 投影 作为 .find() 的第二个参数,仅显示某些字段。我们还附加了 .pretty() 方法以使输出更具可读性。

db.students
.find(
{},
{
_id: 0,
first_name: 1,
last_name: 1,
dob: 1,
}
)
.sort({
dob: 1,
})
.pretty()

上面的查询将返回按出生日期以默认升序排列的学生

{
"first_name" : "Spencer",
"last_name" : "Burton",
"dob" : ISODate("2008-12-04T00:00:00Z")
}
{
"first_name" : "Anthony",
"last_name" : "Apple",
"dob" : ISODate("2009-08-16T00:00:00Z")
}
{
"first_name" : "Carol",
"last_name" : "Apple",
"dob" : ISODate("2010-10-30T00:00:00Z")
}
{
"first_name" : "Nixie",
"last_name" : "Languin",
"dob" : ISODate("2011-02-11T00:00:00Z")
}
{
"first_name" : "Rose",
"last_name" : "Southby",
"dob" : ISODate("2011-03-03T00:00:00Z")
}
{
"first_name" : "Lain",
"last_name" : "Singh",
"dob" : ISODate("2013-06-22T00:00:00Z")
}

要反转排序,请将排序字段设置为 -1 而不是 1

db.students
.find(
{},
{
_id: 0,
first_name: 1,
last_name: 1,
dob: 1,
}
)
.sort({
dob: -1,
})
.pretty()
{
"first_name" : "Lain",
"last_name" : "Singh",
"dob" : ISODate("2013-06-22T00:00:00Z")
}
{
"first_name" : "Rose",
"last_name" : "Southby",
"dob" : ISODate("2011-03-03T00:00:00Z")
}
{
"first_name" : "Nixie",
"last_name" : "Languin",
"dob" : ISODate("2011-02-11T00:00:00Z")
}
{
"first_name" : "Carol",
"last_name" : "Apple",
"dob" : ISODate("2010-10-30T00:00:00Z")
}
{
"first_name" : "Anthony",
"last_name" : "Apple",
"dob" : ISODate("2009-08-16T00:00:00Z")
}
{
"first_name" : "Spencer",
"last_name" : "Burton",
"dob" : ISODate("2008-12-04T00:00:00Z")
}

如何对其他字段进行排序

对于主排序字段包含重复项的情况,MongoDB 可以使用其他字段来控制排序。为此,您可以将额外的字段及其排序顺序传递到传递给 sort() 函数的文档中。

例如,如果我们按 last_namestudent 文档进行排序,我们可以获得基于该字段的学生字母列表

db.students
.find(
{},
{
_id: 0,
first_name: 1,
last_name: 1,
}
)
.sort({
last_name: 1,
})
.pretty()
{ "first_name" : "Carol", "last_name" : "Apple" }
{ "first_name" : "Anthony", "last_name" : "Apple" }
{ "first_name" : "Spencer", "last_name" : "Burton" }
{ "first_name" : "Nixie", "last_name" : "Languin" }
{ "first_name" : "Lain", "last_name" : "Singh" }
{ "first_name" : "Rose", "last_name" : "Southby" }

但是,有两个学生的姓氏为“Apple”,并且在考虑他们的名字时,返回的顺序不是字母顺序。

要解决此问题,我们可以使用 first_name 作为辅助排序字段

db.students
.find(
{},
{
_id: 0,
first_name: 1,
last_name: 1,
}
)
.sort({
last_name: 1,
first_name: 1,
})
.pretty()
{ "first_name" : "Anthony", "last_name" : "Apple" }
{ "first_name" : "Carol", "last_name" : "Apple" }
{ "first_name" : "Spencer", "last_name" : "Burton" }
{ "first_name" : "Nixie", "last_name" : "Languin" }
{ "first_name" : "Lain", "last_name" : "Singh" }
{ "first_name" : "Rose", "last_name" : "Southby" }

在进一步指定之后,结果与我们期望的传统姓名字母顺序匹配。

如何使用嵌入式文档字段进行排序

MongoDB 还可以根据嵌入式文档中包含的值对结果进行排序。为此,请使用 点表示法 深入到嵌入式文档中的相应字段。

例如,您可以根据学生居住的 citystudent 数据进行排序,该城市是每个文档中 address 的组成部分。请记住,使用点表示法时,您需要引用字段名称以确保它们被正确解释

db.students
.find(
{},
{
_id: 0,
first_name: 1,
last_name: 1,
'address.city': 1,
}
)
.sort({
'address.city': 1,
})
.pretty()
{
"first_name" : "Lain",
"last_name" : "Singh",
"address" : {
"city" : "Brighton"
}
}
{
"first_name" : "Carol",
"last_name" : "Apple",
"address" : {
"city" : "Camden"
}
}
{
"first_name" : "Anthony",
"last_name" : "Apple",
"address" : {
"city" : "Camden"
}
}
{
"first_name" : "Rose",
"last_name" : "Southby",
"address" : {
"city" : "Nambles"
}
}
{
"first_name" : "Spencer",
"last_name" : "Burton",
"address" : {
"city" : "Zoofreid"
}
}
{
"first_name" : "Nixie",
"last_name" : "Languin",
"address" : {
"city" : "Zoofreid"
}
}

您可以将此与额外的排序字段结合使用,以确保结果完全按照您希望的方式排序

db.students
.find(
{},
{
_id: 0,
first_name: 1,
last_name: 1,
'address.city': 1,
'address.street': 1,
}
)
.sort({
'address.city': 1,
'address.street.name': 1,
'address.street.number': 1,
last_name: 1,
first_name: 1,
})
.pretty()

在此示例中,我们按以下字段顺序排序

  • 城市
  • 街道名称
  • 街道号码
  • 姓氏
  • 名字

查询结果如下所示

{
"first_name" : "Lain",
"last_name" : "Singh",
"address" : {
"street" : {
"name" : "Plainfield Dr.",
"number" : "308"
},
"city" : "Brighton"
}
}
{
"first_name" : "Anthony",
"last_name" : "Apple",
"address" : {
"street" : {
"name" : "Flint Rd.",
"number" : "803"
},
"city" : "Camden"
}
}
{
"first_name" : "Carol",
"last_name" : "Apple",
"address" : {
"street" : {
"name" : "Flint Rd.",
"number" : "803"
},
"city" : "Camden"
}
}
{
"first_name" : "Rose",
"last_name" : "Southby",
"address" : {
"street" : {
"name" : "Plainfield Dr.",
"number" : "4c"
},
"city" : "Nambles"
}
}
{
"first_name" : "Spencer",
"last_name" : "Burton",
"address" : {
"street" : {
"name" : "Edgecombe St.",
"number" : "2083b"
},
"city" : "Zoofreid"
}
}
{
"first_name" : "Nixie",
"last_name" : "Languin",
"address" : {
"street" : {
"name" : "Kensington Ln.",
"number" : "33"
},
"city" : "Zoofreid"
}
}

现在也是提及您排序的字段不必是您为投影提供的字段的子集的好时机。

例如,我们可以实现完全相同的排序,但仅通过键入以下内容返回学生姓名

db.students
.find(
{},
{
_id: 0,
first_name: 1,
last_name: 1,
}
)
.sort({
'address.city': 1,
'address.street.name': 1,
'address.street.number': 1,
last_name: 1,
first_name: 1,
})
.pretty()

查询返回以下数据

{ "first_name" : "Lain", "last_name" : "Singh" }
{ "first_name" : "Anthony", "last_name" : "Apple" }
{ "first_name" : "Carol", "last_name" : "Apple" }
{ "first_name" : "Rose", "last_name" : "Southby" }
{ "first_name" : "Spencer", "last_name" : "Burton" }
{ "first_name" : "Nixie", "last_name" : "Languin" }

如果您将结果与上一个查询的结果进行比较,您可以验证文档已按相同的顺序返回。

结论

在本文中,我们了解了如何使用 sort() 方法来控制 MongoDB 如何对其查询结果进行排序。我们介绍了单字段排序、按优先级排序多个字段、更改排序序号以及基于嵌入式文档字段进行排序。

文档排序规则结果限制 等功能相结合,排序使您可以精确控制文档和字段之间的比较方式以及它们的返回方式。熟悉这些功能可以帮助您编写更好的查询,并以更接近您使用状态的状态返回数据。

关于作者
Justin Ellingwood

Justin Ellingwood

自 2013 年以来,Justin 一直在撰写关于数据库、Linux、基础设施和开发者工具的文章。他目前与妻子和两只兔子住在柏林。他通常不必以第三人称写作,这对所有相关方来说都是一种解脱。