シェア

はじめに

データの表示または取得時のソートは、ほとんどのデータベースシステムにとって重要な操作であり、他のデータストレージメカニズムと区別するのに役立ちます。格納された順序とは独立して、さまざまなフィールドの順序付け、優先順位付け、および解釈を操作できることは、データベース自体とそれに関連するクエリシステムの両方にとって最も有用な機能の1つです。

MongoDBは、クエリから返されるデータのソート方法を制御する多くの方法を提供しています。このガイドでは、ユースケースに応じてさまざまな方法でデータをソートする方法について説明します。単純なソートと複合ソート、ソート順序の変更方法、およびソートが他の演算子と組み合わせてどのように適用されるかについて説明します。

サンプルデータのセットアップ

ソートの仕組みを示すために、<code class="inline-code">students</code><a href="/dataguide/intro/database-glossary#collections">コレクション</a>に含まれる多数のドキュメントをクエリします。以下のコピーアンドペーストで、クエリする<code class="inline-code">students</code>コレクションを作成し、ドキュメントを挿入できます。

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で結果をソートする基本的なアプローチは、クエリに<code class="inline-code">.sort()</code>メソッドを追加することです。<code class="inline-code">.sort()</code>メソッドは、ソートするフィールドとソート方向を指定するドキュメントを引数として取ります。

結果をソートする最も基本的な方法は、昇順ソートを示す<code class="inline-code">1</code>の値を持つ列名を示す単一フィールドを指定するドキュメントを提供することです

<a href="https://www.mongodb.com/docs/manual/tutorial/project-fields-from-query-results/">MongoDBプロジェクション</a>を<code class="inline-code">.find()</code>の2番目の引数として提供し、特定のフィールドのみを表示することに注意してください。また、出力をより読みやすくするために<code class="inline-code">.pretty()</code>メソッドを追加しています。

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")
}

順序を逆にするには、ソート列を<code class="inline-code">1</code>の代わりに<code class="inline-code">-1</code>に設定します

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は、プライマリソートフィールドに重複が含まれる場合にソートを制御するために追加のフィールドを使用できます。これを行うには、<code class="inline-code">sort()</code>関数に渡すドキュメント内に追加のフィールドとそのソート順序を渡すことができます。

たとえば、<code class="inline-code">student</code>ドキュメントを<code class="inline-code">last_name</code>でソートすると、その1つのフィールドに基づいて生徒のアルファベット順リストを取得できます

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」という姓の生徒が2人おり、返された順序は、彼らの名前も考慮するとアルファベット順ではありません。

これを修正するには、<code class="inline-code">first_name</code>をセカンダリソートフィールドとして使用できます

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は、埋め込みドキュメントに含まれる値に基づいて結果をソートすることもできます。これを行うには、<a href="https://www.mongodb.com/docs/v5.0/core/document/#dot-notation">ドット表記法</a>を使用して、埋め込みドキュメント内の適切なフィールドにドリルダウンします。

たとえば、各ドキュメント内の<code class="inline-code">address</code>のコンポーネントである、生徒が住んでいる<code class="inline-code">city</code>に基づいて<code class="inline-code">student</code>データをソートできます。ドット表記法を使用する場合、フィールド名が正しく解釈されるように引用符で囲む必要があることに注意してください

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" }

結果を前のクエリの結果と比較すると、ドキュメントが同じ順序で返されていることを確認できます。

結論

この記事では、<code class="inline-code">sort()</code>メソッドを使用して、MongoDBがクエリの結果をどのように順序付けるかを制御する方法を見てきました。単一フィールドソート、優先度による複数フィールドソート、ソート順序の変更、および埋め込みドキュメントフィールドに基づくソートについて説明しました。

<a href="https://www.mongodb.com/docs/manual/reference/method/cursor.collation/">ドキュメント照合</a>や<a href="https://www.mongodb.com/docs/manual/reference/method/cursor.limit/">結果制限</a>などの機能と組み合わせることで、ソートを使用すると、ドキュメントとフィールドが互いにどのように比較され、どのように返されるかを正確に制御できます。これらの機能に慣れることで、より良いクエリを作成し、使用方法に近い状態でデータを返すことができます。

著者について
Justin Ellingwood

Justin Ellingwood

Justinは、2013年からデータベース、Linux、インフラストラクチャ、および開発者ツールについて執筆しています。現在、ベルリンで妻と2匹のウサギと暮らしています。彼は通常、三人称で書く必要はありません。これは関係者全員にとって安心です。