MongoDB で 検索結果 を ソートする 方法

0 件のコメント

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