Mongodb 计算查询中的多个日期范围

Mongodb 计算查询中的多个日期范围,mongodb,mongodb-query,aggregation-framework,Mongodb,Mongodb Query,Aggregation Framework,我有下面的聚合查询,它为我提供给定日期范围期间的计数(countA)。在这种情况下,2016年1月1日至2016年3月31日。是否可以添加第二个日期范围,例如2016年1月4日至2016年7月31日,并将其计为countB db.getCollection('customers').aggregate( {$match: {"status": "Closed"}}, {$unwind: "$lines"}, {$match: {"lines.status": "Close

我有下面的聚合查询,它为我提供给定日期范围期间的计数(countA)。在这种情况下,2016年1月1日至2016年3月31日。是否可以添加第二个日期范围,例如2016年1月4日至2016年7月31日,并将其计为countB

db.getCollection('customers').aggregate(
    {$match: {"status": "Closed"}},
    {$unwind: "$lines"},
    {$match: {"lines.status": "Closed"}},
    {$match: {"lines.deliveryMethod": "Tech Delivers"}},
    {$match: {"date": {$gte: new Date('01/01/2016'), $lte: new Date('03/31/2016')}}},
    {$group:{_id:"$lines.productLine",countA: {$sum: 1}}}
)

提前感谢

当然,您还可以大大简化管道阶段,主要是因为后续阶段实际上是单个阶段,并且您应该始终在任何聚合管道的开头使用匹配条件。即使它实际上没有“过滤”数组内容,它至少只选择包含实际匹配项的文档。这大大加快了速度,尤其是对于大型数据集

对于这两个日期范围,这只是一个查询参数。此外,它将在数组过滤完成之前应用,因为毕竟它是一个文档级匹配。同样,在第一个管道中,
$match

db.getCollection(“客户”).aggregate([
//首先过滤所有文档条件。减少要处理的内容。
{“$match”:{
“状态”:“已关闭”,
“行”:{“$elemMatch”:{
“状态”:“已关闭”,
“交付方法”:“技术交付”
}},
“$or”:[
{“日期”:{
“$gte”:新日期(“2016-01-01”),
“$lt”:新日期(“2016-04-01”)
}},
{“日期”:{
“$gte”:新日期(“2016-04-01”),
“$lt”:新日期(“2016-08-01”)
}}
]
}},
//展开阵列
{“$unwind”:“$lines”},
//只过滤匹配的元素
//连续的$match实际上只是一个管道阶段
{“$match”:{
“行.状态”:“已关闭”,
“lines.deliveryMethod”:“技术交付”
}},
//然后对数组中的productline值进行分组
{“$group”:{
“_id”:“$lines.productLine”,
“countA”:{
“$sum”:{
“$cond”:[
{“$and”:[
{“$gte”:[“$date”,新日期(“2016-01-01”)],
{“$lt”:[“$date”,新日期(“2016-04-01”)]
]},
1.
0
]
}
},
“B国”:{
“$sum”:{
“$cond”:[
{“$and”:[
{“$gte”:[“$date”,新日期(“2016-04-01”)],
{“$lt”:[“$date”,新日期(“2016-08-01”)]
]},
1.
0
]
}
}
}}
])
$或
在查找要应用的“任一”范围标准时,基本上“连接”了两个结果集。由于这是在其他参数之外给出的,因此与满足
$或
参数的标准上的其他条件一样,逻辑是一个“AND”条件。注意,
$gte
$lt
组合也是在同一个键上表示“和”条件的另一种形式

由于数组元素上需要“两个”条件,因此应用了。如果您只是直接使用“点表示法”应用它们,那么真正需要的是“至少一个数组元素”匹配每个条件,而不是数组元素匹配“两个”条件

$unwind
后面的过滤可以使用“点表示法”,因为数组元素现在被“反规范化”到单独的文档中。因此,现在每个文档只有一个元素与条件匹配

当您应用时,而不是仅仅使用
{“$sum”:1}
您更愿意“有条件地评估是否使用计数。由于两个日期范围都在结果范围内,您只需要确定当前“汇总”的文档是属于一个日期范围还是另一个。作为“三元”(if/then/else)操作员,这是
$cond
提供的

它查看文档中
“date”
内的值,如果它与条件集(第一个参数-if)匹配,则返回
1
(第二个参数-then),否则返回
0
,实际上不增加当前计数

由于这些是“逻辑”条件,“AND”用逻辑运算符表示,逻辑运算符本身返回
true
false
,要求包含的两个条件都是
true

还要注意
Date
对象构造函数中的更正,因为如果不使用该表示形式中的字符串进行实例化,则生成的
Date
是“localtime”格式,而不是MongoDB存储日期的“UTC”格式。只使用“localtime”“如果你真的这么想的话,人们通常真的不这么想

另一个注意事项是
$lt
日期更改,它应始终比您要查找的最后一个日期“大一天”。请记住,这些是“一天的开始”日期,因此您通常希望所有可能的时间都在该日期内,而不仅仅是直到开始。所以这是“少于第二天”的正确条件


作为记录,对于2.6版本的MongoDB,最好在“you
$unwind
之前”对数组内容进行“预过滤”。这就消除了在“反规范化”过程中生成新文档的开销,这种过程中出现的条件与要应用于数组元素的条件不匹配

对于MongoDB 3.2及更高版本,请使用:

db.getCollection(“客户”).aggregate([
//首先过滤所有文档条件。减少要处理的内容。
{“$match”:{
“状态”:“已关闭”,
“行”:{“$elemMatch”:{
“状态”:“已关闭”,
“交付方法”:“技术交付”
}},
“$or”:[
{“日期”:{
“$gte”:新日期(“2016-01-01”),
“$lt”:新日期(“2016-04-01”)
}},