今回は「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 の フォロー」 お願いします!!