From 377cee1cc79fffe646e018897498b0a6266037d2 Mon Sep 17 00:00:00 2001 From: Dave Cuthbert Date: Wed, 10 Feb 2021 14:52:46 -0500 Subject: [PATCH] DOCS-14133 new dateAdd, dateSubtract agg expressions --- source/includes/extracts-agg-operators.yaml | 8 + .../fact-timezone-description-no-option.rst | 2 +- source/reference/mongodb-extended-json.txt | 2 + source/reference/operator/aggregation.txt | 11 +- .../operator/aggregation/dateAdd.txt | 483 ++++++++++++++++ .../operator/aggregation/dateSubtract.txt | 533 ++++++++++++++++++ source/release-notes/5.0.txt | 24 +- 7 files changed, 1053 insertions(+), 10 deletions(-) create mode 100644 source/reference/operator/aggregation/dateAdd.txt create mode 100644 source/reference/operator/aggregation/dateSubtract.txt diff --git a/source/includes/extracts-agg-operators.yaml b/source/includes/extracts-agg-operators.yaml index 441bd613827..7c7c2bbe8d8 100644 --- a/source/includes/extracts-agg-operators.yaml +++ b/source/includes/extracts-agg-operators.yaml @@ -379,6 +379,10 @@ content: | * - Name - Description + * - :expression:`$dateAdd` + + - Adds a number of time units to a date object. + * - :expression:`$dateDiff` - Returns the difference between two dates. @@ -392,6 +396,10 @@ content: | - Converts a date/time string to a date object. + * - :expression:`$dateSubtract` + + - Subtracts a number of time units from a date object. + * - :expression:`$dateToParts` - Returns a document containing the constituent parts of a date. diff --git a/source/includes/fact-timezone-description-no-option.rst b/source/includes/fact-timezone-description-no-option.rst index e43eabd848c..703f344a023 100644 --- a/source/includes/fact-timezone-description-no-option.rst +++ b/source/includes/fact-timezone-description-no-option.rst @@ -1,4 +1,4 @@ -The timezone of the operation result. ```` must be a +The timezone to carry out the operation. ```` must be a valid :ref:`expression ` that resolves to a string formatted as either an `Olson Timezone Identifier `_ or a diff --git a/source/reference/mongodb-extended-json.txt b/source/reference/mongodb-extended-json.txt index f64642d44f2..3e6c92376d3 100644 --- a/source/reference/mongodb-extended-json.txt +++ b/source/reference/mongodb-extended-json.txt @@ -75,6 +75,8 @@ MongoDB Database Tools .. include:: /includes/extracts/4.2-changes-extended-json-v2.rst +.. _bsontype-list-of-types: + BSON Data Types and Associated Representations ---------------------------------------------- diff --git a/source/reference/operator/aggregation.txt b/source/reference/operator/aggregation.txt index 7e78e7ac12f..a2ac7f9ec1a 100644 --- a/source/reference/operator/aggregation.txt +++ b/source/reference/operator/aggregation.txt @@ -312,6 +312,10 @@ Alphabetical Listing of Expression Operators - Returns the hyperbolic cosine of a value that is measured in radians. + * - :expression:`$dateAdd` + + - Adds a number of time units to a date object. + * - :expression:`$dateDiff` - Returns the difference between two dates. @@ -321,6 +325,9 @@ Alphabetical Listing of Expression Operators - Constructs a BSON Date object given the date's constituent parts. + * - :expression:`$dateSubtract` + + - Subtracts a number of time units from a date object. * - :expression:`$dateToParts` @@ -1011,8 +1018,10 @@ Alphabetical Listing of Expression Operators /reference/operator/aggregation/convert /reference/operator/aggregation/cos /reference/operator/aggregation/cosh - /reference/operator/aggregation/dateDiff + /reference/operator/aggregation/dateAdd + /reference/operator/aggregation/dateDiff /reference/operator/aggregation/dateFromParts + /reference/operator/aggregation/dateSubtract /reference/operator/aggregation/dateToParts /reference/operator/aggregation/dateFromString /reference/operator/aggregation/dateToString diff --git a/source/reference/operator/aggregation/dateAdd.txt b/source/reference/operator/aggregation/dateAdd.txt new file mode 100644 index 00000000000..bd9ed38bb33 --- /dev/null +++ b/source/reference/operator/aggregation/dateAdd.txt @@ -0,0 +1,483 @@ +====================== +$dateAdd (aggregation) +====================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. expression:: $dateAdd + + .. versionadded:: 5.0 + + Increments a :doc:`Date ` object by a + specified number of time units. + + The :expression:`$dateAdd` expression has the following syntax: + + .. code-block:: javascript + + { + $dateAdd: { + startDate: , + unit: , + amount: , + timezone: + } + } + + Returns a :doc:`Date `. The ``startDate`` + can be any expression that resolves to type Date, Timestamp or + ObjectId. No matter which data type is used as input, the value + returned will be a :doc:`Date ` object. + + .. list-table:: + :header-rows: 1 + :widths: 20 20 60 + + * - Field + - Required/Optional + - Description + + * - ``startDate`` + - Required + - The beginning date, in UTC, for the addition operation. The + ``startDate`` can be any + :ref:`expression ` that resolves to + a :ref:`Date `, a + :ref:`Timestamp `, + or an :ref:`ObjectID `. + + * - ``unit`` + - Required + - The ``unit`` used to measure the ``amount`` of time added to + the ``startDate``. The ``unit`` is an + :ref:`expression ` that resolves to + one of the following strings: + + - ``year`` + - ``quarter`` + - ``week`` + - ``month`` + - ``day`` + - ``hour`` + - ``minute`` + - ``second`` + - ``millisecond`` + + * - ``amount`` + - Required + - The number of ``units`` added to the ``startDate``. The + ``amount`` is an :ref:`expression ` + that resolves to an integer or long. The ``amount`` can also + resolve to an integral decimal or a double if that value can + be converted to a long without loss of precision. + + * - ``timezone`` + - Optional + - .. include:: /includes/fact-timezone-description-no-option.rst + + For more information on expressions and types see + :ref:`aggregation-expressions` and :ref:`bson-types`. + +Behavior +-------- + +Time Measurement +~~~~~~~~~~~~~~~~ + +MongoDB follows prevaling database usage and works with time in UTC. The +``dateAdd`` expression always takes a ``startDate`` in UTC and returns +a result in UTC. If the ``timezone`` is specified, the calculation will +be done using the specified ``timezone``. The timezone is especially +important when a calculation involves Daylight Savings Time (DST). + +If the ``unit`` is a ``month``, or larger the operation adjusts to +account for the last day of the month. Adding one ``month`` on the last +day of October, for example, demonstrates the "last-day-of-the-month" +adjustment. + +.. code-block:: javascript + + { + $dateAdd: + { + startDate: ISODate("2020-10-31T12:10:05Z"), + unit: "month", + amount: 1 + } + } + +Notice that the date returned, ``ISODate("2020-11-30T12:10:05Z")``, is +the 30th and not the 31st since November has fewer days than October. + +Time Zone +~~~~~~~~~ + +.. include:: /includes/fact-olson-tz-behavior.rst + +Examples +-------- + +Add a Future Date +~~~~~~~~~~~~~~~~~ + +Consider a collection of customer orders with these documents: + +.. code-block:: javascript + + db.shipping.insertMany( + [ + { custId: 456, purchaseDate: ISODate("2020-12-31") }, + { custId: 457, purchaseDate: ISODate("2021-02-28") }, + { custId: 458, purchaseDate: ISODate("2021-02-26") } + ] + ) + +The normal shipping time is 3 days. You can use ``$dateAdd`` in an +aggregation pipeline to set an ``expectedDeliveryDate`` 3 days in the +future. + +.. code-block:: javascript + :emphasize-lines: 8-13 + + db.shipping.aggregate( + [ + { + $project: + { + expectedDeliveryDate: + { + $dateAdd: + { + startDate: "$purchaseDate", + unit: "day", + amount: 3 + } + } + } + }, + { + $merge: "shipping" + } + ] + ) + +After adding 3 days to the ``purchaseDate`` with ``$dateAdd`` in the +:pipeline:`$project` stage, the :pipeline:`$merge` stage updates the +original documents with the ``expectedDeliveryDate``. + +The resulting documents look like this: + +.. code-block:: javascript + :copyable: false + + { + "_id" : ObjectId("603dd4b2044b995ad331c0b2"), + "custId" : 456, + "purchaseDate" : ISODate("2020-12-31T00:00:00Z"), + "expectedDeliveryDate" : ISODate("2021-01-03T00:00:00Z") + } + { + "_id" : ObjectId("603dd4b2044b995ad331c0b3"), + "custId" : 457, + "purchaseDate" : ISODate("2021-02-28T00:00:00Z"), + "expectedDeliveryDate" : ISODate("2021-03-03T00:00:00Z") + } + { + "_id" : ObjectId("603dd4b2044b995ad331c0b4"), + "custId" : 458, + "purchaseDate" : ISODate("2021-02-26T00:00:00Z"), + "expectedDeliveryDate" : ISODate("2021-03-01T00:00:00Z") + } + +Filter on a Date Range +~~~~~~~~~~~~~~~~~~~~~~ + +Update the ``shipping`` collection from the last example with this code +to add delivery dates to the documents: + +.. code-block:: javascript + + db.shipping.update( + { custId: 456 }, + { $set: { deliveryDate: ISODate( "2021-01-10" ) } } + ) + + db.shipping.update( + { custId: 457 }, + { $set: { deliveryDate: ISODate( "2021-03-01" ) } } + ) + + db.shipping.update( + { custId: 458 }, + { $set: { deliveryDate: ISODate( "2021-03-02" ) } } + ) + +You want to find late shipments. Use ``$dateAdd`` in a +:pipeline:`$match` stage to create a filter that matches documents in a +range of dates defined by a starting point (``$purchaseDate``) and a +time period given by ``$dateAdd``. + +.. code-block:: javascript + :emphasize-lines: 11-16 + + db.shipping.aggregate( + [ + { + $match: + { + $expr: + { + $gt: + [ "$deliveryDate", + { + $dateAdd: + { + startDate: "$purchaseDate", + unit: "day", + amount: 5 + } + } + ] + } + } + }, + { + $project: + { + _id: 0, + custId: 1, + purchased: + { + $dateToString: + { + format: "%Y-%m-%d", + date: "$purchaseDate" + } + }, + delivery: + { + $dateToString: + { + format: "%Y-%m-%d", + date: "$deliveryDate" + } + } + } + } + ] + ) + +The :pipeline:`$match` stage uses :expression:`$gt` and ``$dateAdd`` in +an expression (:query:`$expr`) to compare the actual ``deliveryDate`` +with an expected date. Documents with delivery dates more than 5 days +after the ``purchaseDate`` are passed on to the :pipeline:`$project` +stage. + +The :pipeline:`$project` stage uses the :expression:`$dateToString` +expression to convert the dates to a more readable format. Without the +conversion, MongoDB would return the date in :term:`ISODate` format. + +In this example only one record is returned: + +.. code-block:: javascript + :copyable: false + + { "custId" : 456, "purchased" : "2020-12-31", "delivery" : "2021-01-10" } + +Adjust for Daylight Savings Time +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +All dates are stored internally in UTC time. When a ``timezone`` is +specified, ``$dateAdd`` uses local time to carry out the calculations. +The results are displayed in UTC. + +You have customers in several timezones and you want to see what effect +daylight savings time might have on your billing periods if you bill by +``day`` or by ``hour``. + +Create this collection of connection times: + +.. code-block:: javascript + + db.billing.insertMany( + [ + { + location: "America/New_York", + login: ISODate("2021-03-13T10:00:00-0500"), + logout: ISODate("2021-03-14T18:00:00-0500") + }, + { + location: "America/Mexico_City", + login: ISODate("2021-03-13T10:00:00-00:00"), + logout: ISODate("2021-03-14T08:00:00-0500") + } + ] + ) + + +First add 1 day, then add 24 hours to the ``login`` dates in each +document. + +.. code-block:: javascript + + 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: + { + $dateAdd: + { + startDate: "$login", + unit: "day", + amount: 1, + timezone: "$location" + } + } + } + }, + hours: + { + $dateToString: + { + format: "%Y-%m-%d %H:%M", + date: + { + $dateAdd: + { + 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: + { + $dateAdd: + { + startDate: "$login", + unit: "day", + amount: 1, + timezone: "$location" + } + }, + timezone: "$location" + } + }, + hoursTZInfo: + { + $dateToString: + { + format: "%Y-%m-%d %H:%M", + date: + { + $dateAdd: + { + startDate: "$login", + unit: "hour", + amount: 24, + timezone: "$location" + } + }, + timezone: "$location" + } + }, + } + } + ] + ).pretty() + +The :expression:`$dateToString` expression reformats the output for +readability. Results are summarized here: + +.. list-table:: + :header-rows: 1 + + * - Field + - New York + - Mexico City + + * - Start + - 2021-03-13 15:00 + - 2021-03-13 10:00 + + * - Start, TZ Info + - 2021-03-13 10:00 + - 2021-03-13 04:00 + + * - 1 Day + - 2021-03-14 14:00 + - 2021-03-14 10:00 + + * - 1 Day, TZ Info + - 2021-03-14 10:00 + - 2021-03-14 04:00 + + * - 24 Hours + - 2021-03-14 15:00 + - 2021-03-14 10:00 + + * - 24 Hours, TZ Info + - 2021-03-14 11:00 + - 2021-03-14 04:00 + +The chart highlights several points: + +- Unformatted dates are returned in UTC. The ``$login`` for New York is + UTC -5, however the ``start``, ``days``, and ``hours`` rows display + the time in UTC. + +- March 14th is the start of DST in New York, but not in Mexico. The + calculated time is adjusted when a location switches to DST and + crosses from one ``day`` to the next. + +- DST modifies the length of the ``day``, not the ``hour``. There is no + DST change for ``hours``. There is an only an adjustment for DST when + the measurement ``unit`` is ``day`` or larger and the computation + crosses a clock change in the specified ``timezone``. + +.. seealso:: + + :expression:`$dateSubtract`, :expression:`$dateDiff` + diff --git a/source/reference/operator/aggregation/dateSubtract.txt b/source/reference/operator/aggregation/dateSubtract.txt new file mode 100644 index 00000000000..e0e00494894 --- /dev/null +++ b/source/reference/operator/aggregation/dateSubtract.txt @@ -0,0 +1,533 @@ +=========================== +$dateSubtract (aggregation) +=========================== + +.. default-domain:: mongodb + +.. contents:: On this page + :local: + :backlinks: none + :depth: 1 + :class: singlecol + +Definition +---------- + +.. expression:: $dateSubtract + + .. versionadded:: 5.0 + + Decrements a :doc:`Date ` object by a + specified number of time units. + + The :expression:`$dateSubtract` expression has the following syntax: + + .. code-block:: javascript + + { + $dateSubtract: { + startDate: , + unit: , + amount: , + timezone: + } + } + + Returns a :doc:`Date `. The ``startDate`` + can be any expression that resolves to type Date, Timestamp or + ObjectId. No matter which data type is used as input, the value + returned will be a :doc:`Date ` object. + + .. list-table:: + :header-rows: 1 + :widths: 20 20 60 + + * - Field + - Required/Optional + - Description + + * - ``startDate`` + - Required + - The beginning date, in UTC, for the subtraction operation. + The ``startDate`` can be any + :ref:`expression ` that resolves to + a :ref:`Date `, a + :ref:`Timestamp `, + or an :ref:`ObjectID `. + + * - ``unit`` + - Required + - The ``unit`` used to measure the ``amount`` of time + subtracted from the ``startDate``. The ``unit`` is an + :ref:`expression ` that resolves to + one of the following strings: + + - ``year`` + - ``quarter`` + - ``week`` + - ``month`` + - ``day`` + - ``hour`` + - ``minute`` + - ``second`` + - ``millisecond`` + + * - ``amount`` + - Required + - The number of ``units`` subtracted from the ``startDate``. + The ``amount`` is an + :ref:`expression ` that resolves to + an integer or long. The ``amount`` can also resolve to an + integral decimal and or a double if that value can be + converted to a long without loss of precision. + + * - ``timezone`` + - Optional + - .. include:: /includes/fact-timezone-description-no-option.rst + + For more information on expressions and types see + :ref:`aggregation-expressions` and :ref:`bson-types`. + + +Behavior +-------- + +Time Measurement +~~~~~~~~~~~~~~~~ + +MongoDB follows prevaling database usage and works with time in UTC. The +``dateSubtract`` expression always takes a ``startDate`` in UTC and +returns a result in UTC. If the ``timezone`` is specified, the +calculation will be done using the specified ``timezone``. The timezone +is especially important when a calculation involves Daylight Savings +Time (DST). + +If the ``unit`` is a ``month``, or larger the operation adjusts to +account for the last day of the month. Subtracting one ``month`` on the +last day of March, for example, demonstrates the +"last-day-of-the-month" adjustment. + +.. code-block:: javascript + + { + $dateSubtract: + { + startDate: ISODate("2021-03-31T12:10:05Z"), + unit: "month", + amount: 1 + } + } + +Notice that the date returned, ``ISODate("2021-02-28T12:10:05Z")``, is +the 28th and not the 31st since February has fewer days than March. + +Time Zone +~~~~~~~~~ + +.. include:: /includes/fact-olson-tz-behavior.rst + +Examples +-------- + +Subtract A Fixed Amount +~~~~~~~~~~~~~~~~~~~~~~~ + +Consider a collection of system connection times like these: + +.. code-block:: javascript + + 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") + } + ] + ) + + +Due to a service issue you need to subtract 3 hours from each of the +January 2021 logout times. You can use ``$dateSubtract`` in an +aggregation pipeline to decrement the ``logoutTime``. + +.. code-block:: javascript + :emphasize-lines: 29-34 + + 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" + } + ] + ) + +Two similar comparisons are made in the :pipeline:`$match` stage. First +the :expression:`$year` and :expression:`$month` operators extract the +year and month, respectively, from the ``logoutTime`` Date object. Then +the month and year are checked to see if they :expression:`$match` the +selection targets. Since "January" is encoded as "1", :query:`$expr` +is true when the year and month are equal (:expression:`$eq`) to "2021" +and "1". + +The :pipeline:`$project` stage uses ``$dateSubtract`` to subtract 3 +hours from the ``logoutTime`` of each selected dcoument. + +Finaly, the :pipeline:`$merge` stage updates the collection, writing +the new ``logoutTime`` for the modified documents. + +.. note:: + + Unlike :pipeline:`$out`, the ``$merge`` stage only updates the + matched documents and preserves the rest of the collection. For more + details see: :ref:`$out compared with $merge `. + +The resulting documents look like this: + +.. code-block:: javascript + :copyable: false + + { + "_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") + } + +Filter by Relative Dates +~~~~~~~~~~~~~~~~~~~~~~~~ + +You want to send a survey to clients who have used your service in the +past week. The ``$dateSubtract`` expression can create a range filter +relative to the time the query is executed. + +.. code-block:: javascript + :emphasize-lines: 12-17 + + 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" + } + } + } + } + ] + ) + +The built in aggregation variable :variable:`$$NOW ` returns the +current datetime in :term:`ISODate` format. The :pipeline:`$match` +stage uses the value in :variable:`$$NOW ` to get today's date. +Then the comparison expression (:query:`$expr`) filters the collection +using greater than (:expression:`$gt`) and ``$dateSubtract`` to match +documents that have a ``logoutTime`` in the past week. + +The :pipeline:`$project` stage uses the :expression:`$dateToString` +expression to convert the dates to a more readable format. Without the +conversion MongoDB would return the date in :term:`ISODate` format. +The output shows two customers have logged out in the last week. + +.. code-block:: javascript + :copyable: false + + { "custId" : 459, "loggedOut" : "2021-02-17" } + { "custId" : 460, "loggedOut" : "2021-02-18" } + +Adjust for Daylight Savings Time +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +All dates are stored internally in UTC time. When a ``timezone`` is +specified, ``$dateSubtract`` uses local time to carry out the +calculations. The results are displayed in UTC. + +You have customers in several timezones and you want to see what effect +daylight savings time might have on your billing periods if you bill by +``day`` or by ``hour``. + +Create this collection of connection times: + +.. code-block:: javascript + + 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") + } + ] + ) + + +First subtract 1 day, then subtract 24 hours from the ``login`` dates +in each document. + +.. code-block:: javascript + + 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() + +The :expression:`$dateToString` expression reformats the output for +readability. Results are summarized here: + +.. list-table:: + :header-rows: 1 + + * - Field + - New York + - Mexico City + + * - Start + - 2021-03-14 15:00 + - 2021-03-14 15:00 + + * - Start, TZ Info + - 2021-03-14 11:00 + - 2021-03-14 04:00 + + * - 1 Day + - 2021-03-13 16:00 + - 2021-03-13 15:00 + + * - 1 Day, TZInfo + - 2021-03-13 11:00 + - 2021-03-13 09:00 + + * - 24 Hours + - 2021-03-13 15:00 + - 2021-03-13 15:00 + + * - 24 Hours, TZInfo + - 2021-03-13 10:00 + - 2021-03-13 09:00 + +The chart highlights several points: + +- Unformatted dates are returned in UTC. The ``$login`` for New York is + UTC -5, however the ``start``, ``days``, and ``hours`` rows display + the time in UTC. + +- March 14th is the start of DST in New York, but not in Mexico. The + calculated time is adjusted when a location switches to DST and + crosses from one ``day`` to the next. + +- DST modifies the length of the ``day``, not the ``hour``. There is no + DST change for ``hours``. There is an only an adjustment for DST when + the measurement ``unit`` is ``day`` or larger and the computation + crosses a clock change in the specified ``timezone``. + +.. seealso:: + + :expression:`$dateAdd`, :expression:`$dateDiff` + diff --git a/source/release-notes/5.0.txt b/source/release-notes/5.0.txt index 70f4fb96701..3d94f071e7b 100644 --- a/source/release-notes/5.0.txt +++ b/source/release-notes/5.0.txt @@ -18,6 +18,8 @@ Aggregation New Aggregation Operators ~~~~~~~~~~~~~~~~~~~~~~~~~ +MongoDB 5.0 introduces the following aggregation operators: + .. list-table:: :header-rows: 1 :widths: 20 80 @@ -25,20 +27,26 @@ New Aggregation Operators * - Operator - Description + * - :expression:`$dateAdd` + - Increments a :doc:`Date ` object by a + specified number of time units. + * - :expression:`$dateDiff` - Returns the difference between two dates. + * - :expression:`$dateSubtract` + - Decrements a :doc:`Date ` object by a + specified number of time units. + * - :expression:`$sampleRate` - - MongoDB 5.0 adds the :expression:`$sampleRate` method to - probabilistically select documents from a pipeline at a given - rate. + - Adds the :expression:`$sampleRate` method to probabilistically + select documents from a pipeline at a given rate. * - :expression:`$rand` - - New to MongoDB 5.0 (and 4.4.2), the :expression:`$rand` method - generates a random float value between 0 and 1 each time it is - called. The new :expression:`$sampleRate` operator is based on - ``$rand``. - + - The :expression:`$rand` method generates a random float value + between 0 and 1 each time it is called. The new + :expression:`$sampleRate` operator is based on ``$rand``. (Also + added to MongoDB 4.4.2) General Aggregation Improvements ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~