过滤部分可以使用 $addFields 管道完成,该管道还用于创建要在 $group _id 键和随后的 $match 管道。这样的主干是 $cond 运算符,它将评估需求中的条件以产生所需的日期。
单个 $redact 管道就足够了,但由于您还需要将过滤后的文档分组的逻辑,您不妨使用 $addFields 管道创建具有这种逻辑的字段。
下面的例子演示了这个概念:
db.sensors.aggregate([
{
"$addFields": {
"yearMonthDay": {
"$cond": [
{ /* check if date hour is less than 8 */
"$lt": [
{ "$hour": "$date" },
8
]
},
{ /* subtract one day from a measurement at < 08:00 */
"$dateToString": {
"format": "%Y-%m-%d",
"date": {
"$subtract": [
"$date",
1000 * 60 * 60 * 24
]
}
}
},
{ /* else return actual date */
"$dateToString": {
"format": "%Y-%m-%d",
"date": "$date"
}
}
]
},
"isNight": {
"$or": [
{ "$gte": [ { "$hour": "$date" }, 21 ] },
{ "$lt": [ { "$hour": "$date" }, 8 ] }
]
}
}
},
{ "$match": { "isNight": true } },
{
"$group": {
"_id": "$yearMonthDay",
"count": { "$sum": 1 }
}
}
])
更详细的方法是使用 $switch 案例表达式代替 $cond,如下所示(感谢@Styvane):
db.sensors.aggregate([
{
"$addFields": {
"yearMonthDay": {
"$switch": {
"branches": [
{
"case": { "$lt": [ { "$hour": "$date" }, 8 ] },
"then": { /* subtract one day from a measurement at < 08:00 */
"$dateToString": {
"format": "%Y-%m-%d",
"date": {
"$subtract": [
"$date",
1000 * 60 * 60 * 24
]
}
}
}
},
{
"case": { "$gte": [ { "$hour": "$date" }, 8 ] },
"then": { /* return actual date */
"$dateToString": {
"format": "%Y-%m-%d",
"date": "$date"
}
}
}
]
}
},
"isNight": {
"$or": [
{ "$gte": [ { "$hour": "$date" }, 21 ] },
{ "$lt": [ { "$hour": "$date" }, 8 ] }
]
}
}
},
{ "$match": { "isNight": true } },
{
"$group": {
"_id": "$yearMonthDay",
"count": { "$sum": 1 }
}
}
])