分享到

簡介

對於大多數資料庫系統來說,排序顯示或檢索資料是一項關鍵操作,這有助於將它們與其他資料儲存機制區分開來。能夠獨立於儲存的序數性來操作各種欄位的排序、優先順序和解釋,是資料庫本身及其相關查詢系統最有用的功能之一。

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_name 排序 student 文件,我們可以獲得依該欄位排序的學生字母列表

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 也可以根據嵌入式文件中包含的值對結果進行排序。若要執行此操作,請使用 點記法 深入到嵌入式文件中的適當欄位。

例如,您可以根據 student 資料居住的 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、基礎架構和開發人員工具的文章。他目前與妻子和兩隻兔子住在柏林。他通常不必以第三人稱寫作,這對所有相關方來說都是一種解脫。