今回は「MongoDB で 検索結果 を ソートする 方法」についてまとめます。
思いつく方法としては db.collection.find() を利用するか db.collection.aggregate($sort) を利用するかどちらかかと思います。 今回はその両方をサンプルコードを準備しました。 ソート条件の指定自体はどちらの方法でも同じで、呼び出しまでの記述が少し違うだけです。
サンプルデータ
以下のサンプルデータが入っている環境でのサンプルコードおよび実行結果を見ていきます。
1 2 3 4 5 6 7 8 | > db.fruits.insertMany([ { code: "0101" , name: "apple" , price: 120 }, { code: "0201" , name: "banana" , price: 180 }, { code: "0301" , name: "orange" , price: 130 }, { code: "0302" , name: "grapefruit" , price: 150 }, { code: "0401" , name: "persimmon" , price: 100 }, { code: "0102" , name: "pear" , price: 130 }, ]); |
find() + sort()
sort() はオブジェクトを引数に取り、ソートキーとソート方向(以下参照)を指定します。
キーの指定順はそのままソート優先順(第1ソートキー、第2ソートキー…)となります。
以下のサンプルコードの場合、第1ソートキー code
昇順、第2ソートキー price
昇順、第3ソートキー name
昇順となります。
ソート方向
- 1
- 昇順
- -1
- 降順
コード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | var MongoClient = require( "mongodb" ).MongoClient; MongoClient.connect(URL, (err, client) => { if (err) { client.close(); return ; } var db = client.db( "sample" ); db.collection( "orders" ) .find() .sort({ code: 1, price: 1, name: 1 }) .toArray() .then((docs) => { console.log(docs); }). catch ((err) => { console.log(err); }).then(() => { client.close(); }); }); |
実行 & 結果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | [ { _id: 5a521e9cff3735d50c439d79, code: '0101' , name: 'apple' , price: 120 }, { _id: 5a521e9cff3735d50c439d7a, code: '0201' , name: 'banana' , price: 180 }, { _id: 5a521e9cff3735d50c439d7b, code: '0301' , name: 'orange' , price: 130 }, { _id: 5a521e9cff3735d50c439d7c, code: '0302' , name: 'grapefruit' , price: 150 }, { _id: 5a521e9cff3735d50c439d7d, code: '0401' , name: 'persimmon' , price: 100 }, { _id: 5a521e9cff3735d50c439d7e, code: '0102' , name: 'pear' , price: 130 } ] |
aggregate( $sort )
基本的には find() + sort() と同じです。 ソート順やソート方向の指定方法も同じで呼び方が異なるだけです。
コード
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | var MongoClient = require( "mongodb" ).MongoClient; MongoClient.connect(URL, (err, client) => { if (err) { client.close(); return ; } var db = client.db( "sample" ); db.collection( "fruits" ).aggregate([ { $sort: { datetime: 1, amount: 1, item: 1 } } ]).toArray().then((docs) => { console.log(docs); }). catch ((err) => { console.log(err); }).then(() => { client.close(); }); }); |
実行 & 結果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | [ { _id: 5a521e9cff3735d50c439d79, code: '0101' , name: 'apple' , price: 120 }, { _id: 5a521e9cff3735d50c439d7a, code: '0201' , name: 'banana' , price: 180 }, { _id: 5a521e9cff3735d50c439d7b, code: '0301' , name: 'orange' , price: 130 }, { _id: 5a521e9cff3735d50c439d7c, code: '0302' , name: 'grapefruit' , price: 150 }, { _id: 5a521e9cff3735d50c439d7d, code: '0401' , name: 'persimmon' , price: 100 }, { _id: 5a521e9cff3735d50c439d7e, code: '0102' , name: 'pear' , price: 130 } ] |
$sort ステージの性能
MongoDB のリファレンス を読んでいると、 aggregate() で利用する $sort ステージのメモリーおよびパフォーマンスについては注意点があるようなので、以下にまとめておきます。
メモリー
そもそも aggregate() を利用する時点で 100MB のメモリ制約があります。 回避するためには オプション で allowDiskUse を指定します。 また、 $sort の後に $limit が続く場合、自動的に最初の n 件 だけ処理するよう最適化されるようです。
パフォーマンス
$sort は インデックス が張られていればその恩恵にあずかることができます。 ただし、インデックスが効くのは $project 、 $unwind 、 $group などの前に $sort が実行された場合に限られます。
つまり、上記のメモリーの話とパフォーマンスの話をまとめると、 $sort → $limit → $project / $group と実行すると最適な実装となるようです。
今回は「MongoDB で 検索結果 を ソートする 方法」についてまとめました。 ポイントは以下の通りです。
- sort() も aggregate( $sort ) も同じ
参考になったでしょうか? 本記事がお役に立っていると嬉しいです!!
最後に… このブログに興味を持っていただけた方は、 ぜひ 「Facebookページ に いいね!」または 「Twitter の フォロー」 お願いします!!