$dateSubtract(集計)
定義
$dateSubtract
バージョン 5.0 で追加
指定された時間単位数で
Date()
オブジェクトを減算します。$dateSubtract
式の構文は次のとおりです。{ $dateSubtract: { startDate: <Expression>, unit: <Expression>, amount: <Expression>, timezone: <tzExpression> } } Date()
を返します。startDate
は、Date 型、Timestamp 型、または ObjectId 型に変換される任意の式にできます。どのデータ型が入力に使用されるかにかかわらず、返される値はDate()
オブジェクトになります。フィールド必須/オプション説明startDate
必須
unit
必須
startDate
から差し引かれた時間のamount
を測定するために使用されるunit
です。unit
は、次のいずれかの文字列に変換される式です。year
quarter
week
month
day
hour
minute
second
millisecond
amount
必須
startDate
から差し引かれたunits
の数。amount
は、integer または long に変換される式です。amount
は、その値が精度を失うことなく long に変換できる場合は、integer decimal または double に変換することもできます。timezone
任意
操作を実行するタイムゾーン。
<tzExpression>
は、 Olson タイムゾーン識別子 として形式された string に変換される有効な 式 である必要があります。 または UTC オフセット 。timezone
が指定されていない場合、結果はUTC
に表示されます。形式例Olson タイムゾーン識別子
"America/New_York" "Europe/London" "GMT" UTC オフセット
+/-[hh]:[mm], e.g. "+04:45" +/-[hh][mm], e.g. "-0530" +/-[hh], e.g. "+03" 式と型の詳細については、「式演算子と「BSON types」を参照してください。
動作
時間測定
MongoDB は一般的なデータベースの使用法に従い、UTC の時間で動作します。dateSubtract
式は常に UTC のstartDate
を受け取り、UTC で結果を返します。 timezone
が指定されている場合は、指定されたtimezone
を使用して計算が行われます。 計算に夏時間 (DST) が含まれる場合、タイムゾーンは特に重要です。
unit
が month
またはそれより大きい場合、操作は月の最終日を考慮して調整されます。たとえば、3 月の最終日に month
を 1 つ引くと、「月末日」の調整が行われます。
{ $dateSubtract: { startDate: ISODate("2021-03-31T12:10:05Z"), unit: "month", amount: 1 } }
2 月は 3 月よりも日数が少ないため、返される日付 ISODate("2021-02-28T12:10:05Z")
は 31 日ではなく 28 日であることがわかります。
タイムゾーン
<timezone>
フィールドで Olson タイムゾーン識別子を使用する際、指定されたタイムゾーンに該当する場合、MongoDB は DST オフセットを適用します。
たとえば、次のドキュメントを含む sales
コレクションを考えます。
{ "_id" : 1, "item" : "abc", "price" : 20, "quantity" : 5, "date" : ISODate("2017-05-20T10:24:51.303Z") }
次の集計は、MongoDB がタイムゾーン識別子の DST オフセットを取り扱う方法を示しています。この例では、$hour
演算子と $minute
演算子を使用して、date
フィールドの対応する部分を返します。
db.sales.aggregate([ { $project: { "nycHour": { $hour: { date: "$date", timezone: "-05:00" } }, "nycMinute": { $minute: { date: "$date", timezone: "-05:00" } }, "gmtHour": { $hour: { date: "$date", timezone: "GMT" } }, "gmtMinute": { $minute: { date: "$date", timezone: "GMT" } }, "nycOlsonHour": { $hour: { date: "$date", timezone: "America/New_York" } }, "nycOlsonMinute": { $minute: { date: "$date", timezone: "America/New_York" } } } }])
この操作では、次の結果を返します。
{ "_id": 1, "nycHour" : 5, "nycMinute" : 24, "gmtHour" : 10, "gmtMinute" : 24, "nycOlsonHour" : 6, "nycOlsonMinute" : 24 }
例
固定量の減算
このようなシステム接続時間のコレクションについて考えてみましょう。
db.connectionTime.insertMany( [ { custId: 457, login: ISODate("2020-12-25T19:04:00"), logout: ISODate("2020-12-28T09:04:00") }, { custId: 457, login: ISODate("2021-01-27T05:12:00"), logout: ISODate("2021-01-28T13:05:00") }, { custId: 458, login: ISODate("2021-01-22T06:27:00"), logout: ISODate("2021-01-31T11:00:00") }, { custId: 459, login: ISODate("2021-02-14T20:14:00"), logout: ISODate("2021-02-17T16:05:00") }, { custId: 460, login: ISODate("2021-02-26T02:44:00"), logout: ISODate("2021-02-18T14:13:00") } ] )
サービスの問題により、2021 年 1 月の各ログアウト時間から 3 時間を差し引く必要があります。集計パイプラインで $dateSubtract
を使用して、logoutTime
から減算できます。
db.connectionTime.aggregate( [ { $match: { $expr: { $eq: [ { $year: "$logout" }, 2021 ] }, $expr: { $eq: [ { $month: "$logout" }, 1 ] } } }, { $project: { logoutTime: { $dateSubtract: { startDate: "$logout", unit: "hour", amount: 3 } } } }, { $merge: "connectionTime" } ] )
$match
ステージでは同様の比較が 2 回行われます。まず、$year
演算子と $month
演算子は、logoutTime
Date オブジェクトからそれぞれ年と月を抽出します。次に、月と年が選択対象と一致するかどうかをチェックします。"January" は "1" としてエンコードされるため、$expr
は、年と月が "2021" と "1" に等しい($eq
)場合、true です。
$project
ステージでは、$dateSubtract
を使用して、選択された各ドキュメントの logoutTime
から 3 時間を差し引きます。
最後に、$merge
ステージでコレクションが更新され、変更されたドキュメントの新しい logoutTime
が書き込まれます。
注意
$out
とは異なり、$merge
ステージでは一致したドキュメントのみが更新され、コレクションの残りの部分は保持されます。詳細については、「$out と $merge の比較」を参照してください。
結果のドキュメントは次のようになります。
{ "_id" : ObjectId("603dd94b044b995ad331c0b5"), "custId" : 457, "login" : ISODate("2020-12-25T19:04:00Z"), "logout" : ISODate("2020-12-28T09:04:00Z") } { "_id" : ObjectId("603dd94b044b995ad331c0b6"), "custId" : 457, "login" : ISODate("2021-01-27T05:12:00Z"), "logout" : ISODate("2021-01-28T13:05:00Z"), "logoutTime" : ISODate("2021-01-28T10:05:00Z") } { "_id" : ObjectId("603dd94b044b995ad331c0b7"), "custId" : 458, "login" : ISODate("2021-01-22T06:27:00Z"), "logout" : ISODate("2021-01-31T11:00:00Z"), "logoutTime" : ISODate("2021-01-31T08:00:00Z") } { "_id" : ObjectId("603dd94b044b995ad331c0b8"), "custId" : 459, "login" : ISODate("2021-02-14T20:14:00Z"), "logout" : ISODate("2021-02-17T16:05:00Z") } { "_id" : ObjectId("603dd94b044b995ad331c0b9"), "custId" : 460, "login" : ISODate("2021-02-26T02:44:00Z"), "logout" : ISODate("2021-02-18T14:13:00Z") }
相対日付でフィルタリングする
過去 1 週間にサービスを利用したクライアントにアンケートを送ろうとしています。$dateSubtract
式は、クエリが実行される時間を基準とした範囲フィルターを作成できます。
db.connectionTime.aggregate( [ { $match: { $expr: { $gt: [ "$logoutTime", { $dateSubtract: { startDate: "$$NOW", unit: "week", amount: 1 } } ] } } }, { $project: { _id: 0, custId: 1, loggedOut: { $dateToString: { format: "%Y-%m-%d", date: "$logoutTime" } } } } ] )
組み込み集計変数 $$NOW
は、現在の日時を ISODate 形式で返します。$match
ステージでは、$$NOW
の値を使用して今日の日付を取得します。次に、比較式($expr
)は、「より大きい」($gt
)と $dateSubtract
を使用してコレクションをフィルタリングし、過去 1 週間に logoutTime
があるドキュメントと一致させます。
$project
ステージでは、 $dateToString
式を使用して日付をより読みやすい形式に変換します。 変換を行わない場合、MongoDB は日付をISODate形式で返し、UTC タイムゾーンを想定します。
出力には、過去 1 週間に 2 人のカスタマーがログアウトしたことが示されています。
{ "custId" : 459, "loggedOut" : "2021-02-17" } { "custId" : 460, "loggedOut" : "2021-02-18" }
夏時間に合わせて調整する
すべての日付は、内部的には UTC 時間でストアされます。timezone
が指定されている場合、$dateSubtract
はローカル タイムを使用して計算を実行します。結果は UTC で表示されます。
複数のタイムゾーンのカスタマーがいて、day
や hour
で請求した場合、夏時間が請求期間にどのような影響を与えるかを確認したい場合があります。
この接続時間のコレクションを作成します。
db.billing.insertMany( [ { location: "America/New_York", login: ISODate("2021-03-14T10:00:00-0500"), logout: ISODate("2021-03-14T18:00:00-0500") }, { location: "America/Mexico_City", login: ISODate("2021-03-14T10:00:00-00:00"), logout: ISODate("2021-03-15T08:00:00-0500") } ] )
まず各ドキュメントの login
日付から 1 日を差し引き、次に 24 時間を差し引きます。
db.billing.aggregate( [ { $project: { _id: 0, location: 1, start: { $dateToString: { format: "%Y-%m-%d %H:%M", date: "$login" } }, days: { $dateToString: { format: "%Y-%m-%d %H:%M", date: { $dateSubtract: { startDate: "$login", unit: "day", amount: 1, timezone: "$location" } } } }, hours: { $dateToString: { format: "%Y-%m-%d %H:%M", date: { $dateSubtract: { startDate: "$login", unit: "hour", amount: 24, timezone: "$location" } } } }, startTZInfo: { $dateToString: { format: "%Y-%m-%d %H:%M", date: "$login", timezone: "$location" } }, daysTZInfo: { $dateToString: { format: "%Y-%m-%d %H:%M", date: { $dateSubtract: { startDate: "$login", unit: "day", amount: 1, timezone: "$location" } }, timezone: "$location" } }, hoursTZInfo: { $dateToString: { format: "%Y-%m-%d %H:%M", date: { $dateSubtract: { startDate: "$login", unit: "hour", amount: 24, timezone: "$location" } }, timezone: "$location" } }, } } ] ).pretty()
$dateToString
式は、読みやすいように出力を再フォーマットします。 結果の概要は次のとおりです。
フィールド | New York | メキシコシティ |
---|---|---|
始める | 2021-03-14 15:00 | 2021-03-14 15:00 |
スタート、タイムゾーン情報 | 2021-03-14 11:00 | 2021-03-14 04:00 |
1 日 | 2021-03-13 16:00 | 2021-03-13 15:00 |
1 日、タイムゾーン情報 | 2021-03-13 11:00 | 2021-03-13 09:00 |
24 時間 | 2021-03-13 15:00 | 2021-03-13 15:00 |
24 時間、タイムゾーン情報 | 2021-03-13 10:00 | 2021-03-13 09:00 |
このチャートには、いくつかの重要なポイントがあります。
書式設定されていない日付は UTC で返されます。ニューヨークの
$login
は UTC -5 ですが、start
行、days
行、およびhours
行には時刻が UTC で表示されます。3 月 14 日はニューヨークでは夏時間の開始日ですが、メキシコでは違います。計算された時間は、ロケーションが DST に切り替わり、ある
day
から次の日に移るときに調整されます。DST は、
hour
ではなく、day
の長さを変更します。hours
では、DST の変更はありません。DST の調整は、測定unit
がday
以上で、計算が指定されたtimezone
で時差が生じる場合にのみ行われます。