MongoDB聚合运算符:$dateDiff

文章目录

$dateDiff聚合运算符返回两个日期只差。

语法

js 复制代码
{
   $dateDiff: {
      startDate: <Expression>,
      endDate: <Expression>,
      unit: <Expression>,
      timezone: <tzExpression>,
      startOfWeek: <String>
   }
}

结束日期endDate减去开始日期startDate,返回指定时间单位unit的整数。

参数字段说明:

|字段|是否必须|描述|

|-|-|

|startDate|是|开始时间,可以是任何合法的日期、时间戳或ObjectID表达式|

|startDate|是|结束时间,可以是任何合法的日期、时间戳或ObjectID表达式|

|unit|是|时间单位,可以是结果为yearquarterweekmonthdayhourminutesecondmillisecond的表达式|

|timezone|否|执行操作的时区,<tzExpression>必须是能被解析为奥尔森时区标识符格式的字符串或UTC偏移量,如果timezone不指定,返回值显示为UTC|

|startOfWeek|否|当单位unitweek时使用,默认为星期日,可以是结果为monday (or mon)tuesday (or tue)wednesday (or wed)thursday (or thu)friday (or fri)saturday (or sat)sunday (or sun)之一的字符串表达式|

使用

没有小数单位

$dateDiff表达式返回以指定单位计算的开始日期和结束日期之间的整数差,持续时间是通过计算通过单位边界的次数来确定的,例如,相差 18 个月的两个日期将返回1年的差值,而不是1.5年。

周的开始

除非通过参数startOfWeek指定,否则一周的开始日期为周日。在指定日期的开始日期和结束日期之间开始的任何一周都会被计算在内。周计数不受日历月或日历年的限制。

时区

<timezone>字段中使用 Olson 时区标识符时,MongoDB 会应用 DST 偏移(如果适用于指定的时区)。

例如,包含以下文件的sales集合:

json 复制代码
{
   "_id" : 1,
   "item" : "abc",
   "price" : 20,
   "quantity" : 5,
   "date" : ISODate("2017-05-20T10:24:51.303Z")
}

下面的聚合说明了 MongoDB 如何处理 Olson 时区标识符的 DST 偏移量。示例使用$hour$minute操作符返回日期字段的相应部分:

js 复制代码
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" }
       }
   }
}])

操作返回以下结果:

json 复制代码
{
   "_id": 1,
   "nycHour" : 5,
   "nycMinute" : 24,
   "gmtHour" : 10,
   "gmtMinute" : 24,
   "nycOlsonHour" : 6,
   "nycOlsonMinute" : 24
}

其它细节

该算法使用公历计算日期差异。闰年和夏令时计算在内,但不包括闰秒。返回的差值可以是负数。

举例

持续时间

创建一个消费订单集合:

js 复制代码
db.orders.insertMany(
   [
      {
         custId: 456,
         purchased: ISODate("2020-12-31"),
         delivered: ISODate("2021-01-05")
      },
      {
         custId: 457,
         purchased: ISODate("2021-02-28"),
         delivered: ISODate("2021-03-07")
      },
      {
         custId: 458,
         purchased: ISODate("2021-02-16"),
         delivered: ISODate("2021-02-18")
      }
   ]
)

在下面的例子中:

  • 返回平均交货天数
  • 使用dateDiff计算购买日期和交货日期之间的天数
js 复制代码
 db.orders.aggregate(
    [
       {
          $group:
             {
                 _id: null,
                 averageTime:
                    {
                       $avg:
                          {
                             $dateDiff:
                                {
                                    startDate: "$purchased",
                                    endDate: "$delivered",
                                    unit: "day"
                                }
                           }
                    }
             }
       },
       {
          $project:
             {
                _id: 0,
                numDays:
                   {
                      $trunc:
                         [ "$averageTime", 1 ]
                   }
             }
        }
    ]
)

$group阶段中的$avg累加器使用每个文档上的$dateDiff来获取购买日期和交付日期之间的时间。得出的值将作为averageTime返回。

平均时间的小数部分会在$project阶段被截断 ($trunc),从而产生类似这样的输出结果:

json 复制代码
{ "numDays" : 4.6 }

结果精度

创建subscriptions集合,其中包含订阅的开始日期和结束日期:

js 复制代码
db.subscriptions.insertMany(
   [
      {
         custId: 456,
         start: ISODate("2010-01-01"),
         end: ISODate("2011-01-01")
      },
      {
         custId: 457,
         start: ISODate("2010-01-01"),
         end: ISODate("2011-06-31")
      },
      {
         custId: 458,
         start: ISODate("2010-03-01"),
         end: ISODate("2010-04-30")
      }
   ]
)

$dateDiff表达式返回以整数单位表示的时间差,单位中没有小数部分。例如,以年为单位计算时,就没有半年。

在本例中,请注意单位的改变对返回精度的影响:

js 复制代码
db.subscriptions.aggregate(
   [
      {
         $project:
            {
               Start: "$start",
               End: "$end",
               years:
                  {
                     $dateDiff:
                        {
                           startDate: "$start",
                           endDate: "$end",
                           unit: "year"
                        }
                  },
               months:
                  {
                     $dateDiff:
                        {
                           startDate: "$start",
                           endDate: "$end",
                           unit: "month"
                        }
                  },
               days:
                  {
                     $dateDiff:
                        {
                           startDate: "$start",
                           endDate: "$end",
                           unit: "day"
                        }
                  },
               _id: 0
            }
       }
   ]
 )

结果汇总如下表所示:

Start End Years Months Days
2010-01-01 2011-01-01 1 12 365
2010-01-01 2011-07-01 1 18 546
2010-03-01 2010-04-30 0 1 60

计数只在新单位开始时递增,因此第二行中的18个月为1年,第三行中的60天为1个月。

每月周数

创建一个months集合:

js 复制代码
db.months.insertMany(
     [
        {
           month: "January",
           start: ISODate("2021-01-01"),
           end: ISODate("2021-01-31")
        },
        {
           month: "February",
           start: ISODate("2021-02-01"),
           end: ISODate("2021-02-28")
        },
        {
           month: "March",
           start: ISODate("2021-03-01"),
           end: ISODate("2021-03-31")
        },
     ]
   )

可以使用以下代码更改每周的开始时间,并计算出每月的周数:

js 复制代码
db.months.aggregate(
   [
      {
         $project:
            {
               wks_default:
                  {
                     $dateDiff:
                        {
                           startDate: "$start",
                           endDate: "$end",
                           unit: "week"
                        }
                  },
               wks_monday:
                  {
                     $dateDiff:
                        {
                           startDate: "$start",
                           endDate: "$end",
                           unit: "week",
                           startOfWeek: "Monday"
                        }
                  },
               wks_friday:
                  {
                     $dateDiff:
                        {
                           startDate: "$start",
                           endDate: "$end",
                           unit: "week",
                           startOfWeek: "fri"
                        }
                  },
               _id: 0
            }
       }
   ]
 )

下表对结果进行了汇总:

Month Sunday Monday Friday
January 5 4 4
February 4 3 4
March 4 4 4

从结果来看:

  • 当 "周初 "是周日时,2021年1月的第5周从31日开始。
  • 由于31日是周日,且位于开始日期和结束日期之间,因此计数会增加一周。
  • 即使日历周在结束日期之后或在下一个日历期间结束,周计数也会递增。
相关推荐
Mr.134 分钟前
数据库的三范式是什么?
数据库
Cachel wood10 分钟前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架
Python之栈17 分钟前
【无标题】
数据库·python·mysql
风_流沙29 分钟前
java 对ElasticSearch数据库操作封装工具类(对你是否适用嘞)
java·数据库·elasticsearch
亽仒凣凣37 分钟前
Windows安装Redis图文教程
数据库·windows·redis
亦世凡华、1 小时前
MySQL--》如何在MySQL中打造高效优化索引
数据库·经验分享·mysql·索引·性能分析
YashanDB1 小时前
【YashanDB知识库】Mybatis-Plus调用YashanDB怎么设置分页
数据库·yashandb·崖山数据库
ProtonBase1 小时前
如何从 0 到 1 ,打造全新一代分布式数据架构
java·网络·数据库·数据仓库·分布式·云原生·架构
云和数据.ChenGuang6 小时前
Django 应用安装脚本 – 如何将应用添加到 INSTALLED_APPS 设置中 原创
数据库·django·sqlite
woshilys7 小时前
sql server 查询对象的修改时间
运维·数据库·sqlserver