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日是周日,且位于开始日期和结束日期之间,因此计数会增加一周。
  • 即使日历周在结束日期之后或在下一个日历期间结束,周计数也会递增。
相关推荐
全能全知者4 分钟前
docker快速安装与配置mongoDB
mongodb·docker·容器
齐 飞6 分钟前
MongoDB笔记01-概念与安装
前端·数据库·笔记·后端·mongodb
云空7 分钟前
《Python 与 SQLite:强大的数据库组合》
数据库·python·sqlite
暮毅11 分钟前
10.Node.js连接MongoDb
数据库·mongodb·node.js
wowocpp15 分钟前
ubuntu 22.04 server 格式化 磁盘 为 ext4 并 自动挂载 LTS
服务器·数据库·ubuntu
成富37 分钟前
文本转SQL(Text-to-SQL),场景介绍与 Spring AI 实现
数据库·人工智能·sql·spring·oracle
songqq2738 分钟前
SQL题:使用hive查询各类型专利top 10申请人,以及对应的专利申请数
数据库·sql
计算机学长felix41 分钟前
基于SpringBoot的“校园交友网站”的设计与实现(源码+数据库+文档+PPT)
数据库·spring boot·毕业设计·交友
小码的头发丝、1 小时前
Django中ListView 和 DetailView类的区别
数据库·python·django
Karoku0662 小时前
【企业级分布式系统】Zabbix监控系统与部署安装
运维·服务器·数据库·redis·mysql·zabbix