分享到

简介

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

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 数据进行排序,city 是每个文档中 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

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