$sort(集計)
定義
互換性
次の環境でホストされる配置には $sort
を使用できます。
MongoDB Atlas はクラウドでの MongoDB 配置のためのフルマネージド サービスです
MongoDB Enterprise: サブスクリプションベースの自己管理型 MongoDB バージョン
MongoDB Community: ソースが利用可能で、無料で使用できる自己管理型の MongoDB のバージョン
構文
$sort
ステージのプロトタイプ形式は次のとおりです。
{ $sort: { <field1>: <sort order>, <field2>: <sort order> ... } }
$sort
は、並べ替えるフィールドとそれぞれの並べ替え順序を指定するドキュメントを受け取ります。 <sort order>
には次のいずれかの値を指定できます。
値 | 説明 |
---|---|
| 昇順にソートします。 |
| 降順にソートします。 |
|
|
複数のフィールドでソートする場合、ソート順序は左から右に評価されます。たとえば、上記のフォームでは、ドキュメントは最初に <field1>
でソートされます。次に、同じ <field1>
値を持つドキュメントが <field2>
によってさらにソートされます。
動作
パフォーマンス
$sort
はブロッキング ステージであり、パイプラインはデータを処理する前にすべての入力データが検索されるまで待機します。ブロッキング ステージは、複数のステージを持つパイプラインの並列処理を減らすため、パフォーマンスを低下させる可能性があります。ブロッキング ステージでは、大規模なデータセットに対して大量のメモリが使用される場合もあります。
制限
最大 32 個のキーでソートすることができます。
重複するフィールドを含むソート パターンを指定すると、エラーが発生します。
ソートの一貫性
MongoDB では、コレクション内のドキュメントを特定の順序で保存することはありません。重複する値を含むフィールドでソートする場合、それらの値を含むドキュメントは任意の順序で返されます。
一貫したソート順序が必要な場合は、一意の値を含むフィールドを少なくとも 1 つ含めてソートしてください。これを保証する最も簡単な方法は、_id
フィールドをソートのクエリに含めることです。
次の restaurant
コレクションについて考えてみます。
db.restaurants.insertMany( [ { "_id" : 1, "name" : "Central Park Cafe", "borough" : "Manhattan"}, { "_id" : 2, "name" : "Rock A Feller Bar and Grill", "borough" : "Queens"}, { "_id" : 3, "name" : "Empire State Pub", "borough" : "Brooklyn"}, { "_id" : 4, "name" : "Stan's Pizzaria", "borough" : "Manhattan"}, { "_id" : 5, "name" : "Jane's Deli", "borough" : "Brooklyn"}, ] )
次のコマンドは、 $sort
ステージを使用して borough
フィールドでソートします。
db.restaurants.aggregate( [ { $sort : { borough : 1 } } ] )
この例では、borough
フィールドに Manhattan
と Brooklyn
の両方で重複する値が含まれているため、ソート順序に一貫性がない可能性があります。ドキュメントは borough
のアルファベット順に返されますが、borough
の値が重複しているドキュメントでは、同じソートを複数回実行すると順序が異なる場合があります。たとえば、上記のコマンドを 2 回実行した結果を次に示します。
{ "_id" : 3, "name" : "Empire State Pub", "borough" : "Brooklyn" } { "_id" : 5, "name" : "Jane's Deli", "borough" : "Brooklyn" } { "_id" : 1, "name" : "Central Park Cafe", "borough" : "Manhattan" } { "_id" : 4, "name" : "Stan's Pizzaria", "borough" : "Manhattan" } { "_id" : 2, "name" : "Rock A Feller Bar and Grill", "borough" : "Queens" } { "_id" : 5, "name" : "Jane's Deli", "borough" : "Brooklyn" } { "_id" : 3, "name" : "Empire State Pub", "borough" : "Brooklyn" } { "_id" : 4, "name" : "Stan's Pizzaria", "borough" : "Manhattan" } { "_id" : 1, "name" : "Central Park Cafe", "borough" : "Manhattan" } { "_id" : 2, "name" : "Rock A Feller Bar and Grill", "borough" : "Queens" }
borough
の値はまだアルファベット順にソートされていますが、borough
の値が重複しているドキュメントの順序(Manhattan
と Brooklyn
)は同じではありません。
一貫性のあるソート を実現するには、一意の値のみを含むフィールドをソートに追加します。 次のコマンドは、 $sort
ステージを使用して、 borough
フィールドと_id
フィールドの両方でソートします。
db.restaurants.aggregate( [ { $sort : { borough : 1, _id: 1 } } ] )
_id
フィールドには常に一意の値のみが含まれることが保証されているため、同じソートを複数回実行しても返されるソート順序は常に同じになります。
配列フィールドによるソート
MongoDB が配列値フィールドでドキュメントをソートする場合、ソートキーは昇順か降順かのどちらかによって異なります。
昇順ソートでは、ソートキーは配列内の最小値になります。
降順ソートでは、ソートキーは配列内の最も高い値になります。
クエリフィルターは、ソート キーの選択に影響しません。
たとえば、次のドキュメントを使用してshoes
コレクションを作成します。
db.shoes.insertMany( [ { _id: 'A', sizes: [ 7, 11 ] }, { _id: 'B', sizes: [ 8, 9, 10 ] } ] )
次のクエリは、ドキュメントをsizes
フィールドで昇順と降順でソートします。
// Ascending sort db.shoes.aggregate( [ { $sort: { sizes: 1 } } ] ) // Descending sort db.shoes.aggregate( [ { $sort: { sizes: -1 } } ] )
上記のクエリではどちらのクエリでも、最初に_id: 'A'
を持つドキュメントが返されます。これは、 7
と11
のサイズがそれぞれ、 sizes
配列のエントリの最小値と最大値であるためです。
例
昇順および降順ソート
ソートの基準となるフィールドについては、次の例のように、ソート順序を 1
または -1
に設定して、それぞれ昇順または降順のソートを指定します。
db.users.aggregate( [ { $sort : { age : -1, posts: 1 } } ] )
この操作は、users
コレクション内のドキュメントを age
フィールドの降順でソートし、次に posts
フィールドの値の昇順でソートします。
ソート操作で異なる BSON types の値を比較する場合、MongoDB は最小値から最大値の順に次の比較順序を使用します。
MinKey(内部型)
null
数値(ints、longs、doubles、decimals)
シンボル、文字列
オブジェクト
配列
BinData
ObjectId
ブール値
日付
タイムスタンプ
正規表現
JavaScript コード
MaxKey(内部型)
特定のタイプの比較およびソート順序の詳細については、「比較およびソート順序」を参照してください。
Text Score Metadata Sort
注意
$text
は、自己管理型(Atlas 以外)配置に対するテキスト クエリ機能を提供します。MongoDB Atlas でホストされているデータに対して、MongoDB は改良された全文クエリ ソリューションである Atlas Search を提供します。
$text
を含むパイプラインでは、{ $meta: "textScore"
}
式を使用して関連性スコアを降順に並べ替えることができます。{ <sort-key> }
ドキュメントで、{ $meta: "textScore" }
式を無作為のフィールド名に設定します。フィールド名はクエリ システムによって無視されます。以下に例を挙げます。
db.users.aggregate( [ { $match: { $text: { $search: "operating" } } }, { $sort: { score: { $meta: "textScore" }, posts: -1 } } ] )
この操作では、 $text
演算子を使用してドキュメントを一致させ、最初に"textScore"
メタデータを降順でソートし、次にposts
フィールドで降順にソートします。 ソート ドキュメント内のscore
フィールド名はクエリ システムによって無視されます。 このパイプラインでは、 "textScore"
メタデータはプロジェクションに含まれておらず、一致するドキュメントの一部として返されません。 詳しくは、 $meta
を参照してください。
$sort
演算子とメモリ
$sort
+$limit
メモリの最適化
$sort
が$limit
に先行し、途中にドキュメント数を変更するステージがない場合、オプティマイザは$limit
を$sort
に統合します。 これにより、 $sort
操作の進行中に上位 のn
結果のみが保持できます。ここでは、 n
は指定された制限であり、MongoDB はメモリにn
個の項目のみを保存するだけで済むようになります。 この最適化は、 allowDiskUse
がtrue
で、かつn
項目が集計メモリの制限 を超えている場合でも、引き続き適用されます。
最適化はリリースに応じて変更される場合があります。
$sort
およびメモリ制限
MongoDB 6.0 以降、 100 MB 以上のメモリを必要とするパイプライン ステージでは、デフォルトで一時ファイルをディスクに書き込みます。これらの一時ファイルはパイプラインの実行中ずっと残り、インスタンスのストレージ容量に影響を与える可能性があります。以前のバージョンの MongoDB では、この動作を有効にするには、個々の find
コマンドと aggregate
コマンドに { allowDiskUse: true }
を渡す必要がありました。
個々の find
と aggregate
コマンドは、次のいずれかの方法で allowDiskUseByDefault
パラメーターを上書きできます。
allowDiskUseByDefault
がfalse
に設定されている場合に{ allowDiskUse: true }
を使用して一時ファイルをディスクに書き込むことを許可するallowDiskUseByDefault
がtrue
に設定されている場合に{ allowDiskUse: false }
を使用して一時ファイルがディスクに書き込むことを禁止する
注意
MongoDB Atlas でストレージが長時間実行クエリにより一時ファイルで満杯にするのを防ぐために、ストレージのオートスケーリングを構成することを推奨します。
Atlas クラスターでストレージのオートスケーリングが使用されている場合、一時ファイルによってクラスターが 1 つ上のストレージ階層にスケーリングされる場合があります。
詳しくは、「集計パイプラインの制限」を参照してください。
$sort
演算子とパフォーマンス
$sort
演算子は、パイプラインの最初のステージで使用される場合、または$match
ステージのみの前にある場合は、インデックスを利用できます。
シャーディングされたクラスターで$sort
を使用すると、各シャードはインデックスを使用して結果ドキュメントをソートします(使用可能な場合)。 次に、 mongos
またはシャードの 1 つがストリーム マージソートを実行します。