今回は「MongoDB で 検索結果 を ソートする 方法」についてまとめます。
思いつく方法としては db.collection.find() を利用するか db.collection.aggregate($sort) を利用するかどちらかかと思います。 今回はその両方をサンプルコードを準備しました。 ソート条件の指定自体はどちらの方法でも同じで、呼び出しまでの記述が少し違うだけです。
サンプルデータ
以下のサンプルデータが入っている環境でのサンプルコードおよび実行結果を見ていきます。
> 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
- 降順
コード
var MongoClient = require("mongodb").MongoClient; var URL = "mongodb://localhost:27017"; 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(); }); });
実行 & 結果
[ { _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() と同じです。 ソート順やソート方向の指定方法も同じで呼び方が異なるだけです。
コード
var MongoClient = require("mongodb").MongoClient; var URL = "mongodb://localhost:27017"; 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(); }); });
実行 & 結果
[ { _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 の フォロー」 お願いします!!