MongoDB の日付操作

MongoDBBeginner
オンラインで実践に進む

はじめに

この実験では、MongoDB で日付を扱う方法を学びます。日付値を持つドキュメントの挿入、特定の日付範囲内のドキュメントのクエリ、表示用の日付フィールドのフォーマット、既存の日付フィールドの更新、日付によるコレクションのソートを練習します。この実験は、MongoDB の日付関連機能に関する包括的で実践的なガイドを提供します。これらの機能は、時系列データの管理、スケジューリング、ログ記録アプリケーションに不可欠です。

日付値を持つドキュメントの挿入

最初のステップでは、MongoDB サーバーに接続し、日付値を含むいくつかのドキュメントを挿入します。これは、後続のステップで実行するクエリと操作の基盤となります。

まず、ターミナルで mongosh コマンドを実行して MongoDB シェルを開きます。これにより、実行中の MongoDB インスタンスに接続されます。

mongosh

シェルに入ると、test> のようなプロンプトが表示されます。datelab という新しいデータベースに切り替えましょう。データベースが存在しない場合、MongoDB は最初のデータ挿入時に自動的に作成します。

use datelab

次に、events という名前の新しいコレクションに 3 つのドキュメントを挿入します。各ドキュメントはイベントを表し、日付を含みます。MongoDB は日付を BSON Date オブジェクトとして保存します。これは new Date() コンストラクタを使用して作成できます。

以下のドキュメントを一つずつ挿入してください。最初のドキュメントは ISO-8601 日付文字列を使用し、2 番目のドキュメントは現在の日時を使用し、3 番目のドキュメントはミリ秒単位の Unix タイムスタンプを使用します。

db.events.insertOne({
    event_name: "Conference",
    date: new Date("2024-06-15T10:30:00Z")
})
db.events.insertOne({
    event_name: "System Maintenance",
    timestamp: new Date()
})
db.events.insertOne({
    event_name: "Project Deadline",
    timestamp: new Date(1718476800000)
})

ドキュメントを挿入した後、find() メソッドを使用して、それらが正しく追加されたことを確認できます。このメソッドはコレクション内のすべてのドキュメントを取得します。

db.events.find()

出力は以下のようになりますが、_id の値と「System Maintenance」の timestamp はあなたの場合と異なります。

[
  {
    _id: ObjectId("65d38f8a1c2d3e4f5a6b7c8d"),
    event_name: 'Conference',
    date: ISODate('2024-06-15T10:30:00.000Z')
  },
  {
    _id: ObjectId("65d38f9c1c2d3e4f5a6b7c8e"),
    event_name: 'System Maintenance',
    timestamp: ISODate('2024-02-19T14:55:24.123Z')
  },
  {
    _id: ObjectId("65d38fb11c2d3e4f5a6b7c8f"),
    event_name: 'Project Deadline',
    timestamp: ISODate('2024-06-15T18:00:00.000Z')
  }
]

これで、日付値を持つドキュメントを正常に挿入できました。次のステップでは、これらのドキュメントを日付に基づいてクエリする方法を学びます。

日付範囲によるドキュメントのクエリ

コレクションにデータが格納されたので、特定の日付範囲内のドキュメントを見つけるためのクエリを実行できます。これは、スケジュールされたイベント、ログ、または時間的制約のあるデータを扱うアプリケーションで一般的な要件です。

まず、クエリをより面白くするために、コレクションにさらにイベントを追加しましょう。ここでは insertMany() メソッドを使用して、一度に 3 つのドキュメントを追加します。

db.events.insertMany([
    {
        event_name: "Summer Conference",
        date: new Date("2024-07-15T09:00:00Z")
    },
    {
        event_name: "Winter Workshop",
        date: new Date("2024-01-20T14:30:00Z")
    },
    {
        event_name: "Spring Meetup",
        date: new Date("2024-04-10T11:15:00Z")
    }
])

これで、合計 6 つのイベントがあります。次に、2024 年 6 月 1 日以降に発生したすべてのイベントを見つけましょう。これを行うには、「より大きい」演算子である $gt を使用します。

db.events.find({
    date: { $gt: new Date("2024-06-01") }
})

次に、2024 年前半、具体的には 1 月 1 日から 6 月 1 日までのすべてのイベントを見つけましょう。これには、「以上」演算子 ($gte) と「未満」演算子 ($lt) を組み合わせることができます。

db.events.find({
    date: {
        $gte: new Date("2024-01-01"),
        $lt: new Date("2024-06-01")
    }
})

このクエリは、「Winter Workshop」と「Spring Meetup」のイベントを返します。出力は以下のようになります。

[
  {
    _id: ObjectId("65d392a11c2d3e4f5a6b7c91"),
    event_name: 'Winter Workshop',
    date: ISODate('2024-01-20T14:30:00.000Z')
  },
  {
    _id: ObjectId("65d392a11c2d3e4f5a6b7c92"),
    event_name: 'Spring Meetup',
    date: ISODate('2024-04-10T11:15:00.000Z')
  }
]

これらの例は、比較演算子 ($gt, $gte, $lt, $lte) を使用して、日付フィールドに基づいてドキュメントを効果的にフィルタリングする方法を示しています。

集計による日付出力のフォーマット

多くの場合、日付を特定の、人間が読める形式で表示する必要があります。MongoDB の集計フレームワークは、このための強力なツールを提供します。このステップでは、$dateToString 演算子を使用して日付フィールドをフォーマットします。

集計フレームワークは、ステージのパイプラインを通じてドキュメントを処理します。ここでは $project ステージを使用してドキュメントを再構成し、新しいフォーマット済み日付フィールドを作成します。

イベントの date フィールドを YYYY-MM-DD 形式にフォーマットしましょう。このクエリは、date フィールドを持つドキュメントのみを処理します。

db.events.aggregate([
    {
        $project: {
            event_name: 1,
            formatted_date: {
                $dateToString: {
                    format: "%Y-%m-%d",
                    date: "$date"
                }
            }
        }
    }
])

このコマンドの内訳を見てみましょう。

  • db.events.aggregate([...]): events コレクションで集計パイプラインを開始します。
  • $project: ドキュメントを再構成するステージです。event_name を含め、新しいフィールド formatted_date を作成します。
  • $dateToString: 日付オブジェクトを文字列に変換する演算子です。
  • format: "%Y-%m-%d": 出力形式を指定します。%Y は年、%m は月、%d は日です。
  • date: "$date": 元のドキュメントから入力日付フィールドを指定します。$ プレフィックスはフィールドパスを示します。

出力には、元のイベント名と新しくフォーマットされた日付文字列が表示されます。date フィールドを持たないドキュメント(「System Maintenance」など)は結果から除外されることに注意してください。

[
  { _id: ObjectId("..."), event_name: 'Conference', formatted_date: '2024-06-15' },
  { _id: ObjectId("..."), event_name: 'Summer Conference', formatted_date: '2024-07-15' },
  { _id: ObjectId("..."), event_name: 'Winter Workshop', formatted_date: '2024-01-20' },
  { _id: ObjectId("..."), event_name: 'Spring Meetup', formatted_date: '2024-04-10' }
]

$year$month のような演算子を使用して、年や月などの日付の個々のコンポーネントを抽出することもできます。

db.events.aggregate([
    {
        $project: {
            event_name: 1,
            year: { $year: "$date" },
            month: { $month: "$date" },
            day: { $dayOfMonth: "$date" }
        }
    }
])

これにより、日付情報の処理と表示方法を細かく制御できます。

日付フィールドの更新

データは常に静的であるとは限りません。イベントのリスケジュールや変更タイムスタンプの追加など、日付フィールドを更新する必要がある場合があります。このステップでは、さまざまな更新演算子を使用して日付フィールドを更新する方法を学びます。

まず、「Conference」イベントを新しい日付にリスケジュールしましょう。ここでは updateOne() メソッドを使用して単一のドキュメントを対象とし、$set 演算子を使用してその date フィールドを変更します。

db.events.updateOne(
    { event_name: "Conference" },
    {
        $set: {
            date: new Date("2024-09-01T10:00:00Z"),
            status: "Rescheduled"
        }
    }
)

次に、バルク更新を実行しましょう。2024 年 5 月 1 日より前に発生したすべてのイベントを「Archived」としてマークします。また、この更新が行われた日時を記録するために、新しいフィールド last_modified を追加します。updateMany() メソッドは一致するすべてのドキュメントを変更し、$currentDate 演算子はフィールドを現在のサーバー時刻に設定するのに最適です。

db.events.updateMany(
    { date: { $lt: new Date("2024-05-01") } },
    {
        $set: { status: "Archived" },
        $currentDate: { last_modified: true }
    }
)

すべてのドキュメントを取得して変更を確認しましょう。.pretty() メソッドは非推奨になったため、find() のみを使用します。

db.events.find()

「Conference」の日付とステータスが新しくなっていることがわかります。「Winter Workshop」と「Spring Meetup」は「Archived」としてマークされ、last_modified タイムスタンプが追加されています。

アーカイブされたイベントの出力例:

{
 "_id" : ObjectId("..."),
 "event_name" : "Winter Workshop",
 "date" : ISODate("2024-01-20T14:30:00Z"),
 "status" : "Archived",
 "last_modified" : ISODate("2024-02-19T15:10:00Z")
}

これらの操作は、ドキュメント内の日付関連情報を正確にどのように変更できるかを示しています。

日付によるドキュメントのソート

最後に学ぶ基本的な操作はソートです。イベントを時系列順に表示することは一般的な要件です。MongoDB では、日付を含む任意のフィールドでクエリ結果を簡単にソートできます。

ドキュメントをソートするには、find() クエリに .sort() メソッドを追加します。sort() メソッドは、ソートするフィールドとそのソート順を指定するドキュメントを受け取ります。値 1 は昇順(古い順)、-1 は降順(新しい順)を示します。

すべてのイベントを date フィールドで昇順にソートして取得してみましょう。

db.events.find().sort({ date: 1 })

これにより、イベントは「Winter Workshop」(最も古い)から「Summer Conference」(最も新しい)の順にリストされます。date フィールドを持たないドキュメントは、クエリに含まれている場合、最初にソートされます。

次に、イベントを降順にソートして、最新のイベントを最初に表示しましょう。

db.events.find().sort({ date: -1 })

ソートとフィルタリングを組み合わせることもできます。たとえば、アーカイブされていないすべてのイベントを検索し、日付でソートしてみましょう。

db.events.find({ status: { $ne: "Archived" } }).sort({ date: 1 })

出力には、アーカイブされていないイベントが時系列順に表示されます。

[
  {
    _id: ObjectId("..."),
    event_name: 'System Maintenance',
    timestamp: ISODate("...")
  },
  {
    _id: ObjectId("..."),
    event_name: 'Project Deadline',
    timestamp: ISODate('2024-06-15T18:00:00.000Z')
  },
  {
    _id: ObjectId("..."),
    event_name: 'Summer Conference',
    date: ISODate('2024-07-15T09:00:00.000Z')
  },
  {
    _id: ObjectId("..."),
    event_name: 'Conference',
    date: ISODate('2024-09-01T10:00:00.000Z'),
    status: 'Rescheduled'
  }
]

ソートは、時間順のデータを意味のある方法で表示するための重要なツールです。終了したら、exit と入力するか Ctrl+D を押して MongoDB シェルを終了できます。

まとめ

この実験では、MongoDB で日付を扱うための基本的なテクニックを学びました。まず、さまざまな形式の日付値を持つドキュメントを挿入しました。次に、比較演算子を使用して日付範囲に基づいてドキュメントをクエリする練習をしました。その後、集計フレームワークを使用して日付フィールドをフォーマットし、可読性を向上させました。また、日付フィールドを更新し、変更タイムスタンプを追加する方法も学びました。最後に、コレクションを日付でソートしてデータを時系列順に表示する方法を習得しました。これらのスキルは、MongoDB で時間ベースのデータを扱うすべての開発者にとって不可欠です。