基于离散日期范围的分组
Group based on discrete date ranges
我是 MongoDB 的新手,我一直在努力使特定查询正常工作,但运气不佳。
我有一个包含数百万个具有日期和数量的文档的集合,我想获取特定时间段的聚合。
例如,我想获取 1/1/2015 - 15/1/2015
和 1/2/2015 - 15/2/2015
之间期间的计数、金额总和
样本集是
{ "_id" : "148404972864202083547392254", "account" : "3600", "amount" : 50, "date" : ISODate("2017-01-01T12:02:08.642Z")}
{ "_id" : "148404972864202085437392254", "account" : "3600", "amount" : 50, "date" : ISODate("2017-01-03T12:02:08.642Z")}
{ "_id" : "148404372864202083547392254", "account" : "3600", "amount" : 70, "date" : ISODate("2017-01-09T12:02:08.642Z")}
{ "_id" : "148404972864202083547342254", "account" : "3600", "amount" : 150, "date" : ISODate("2017-01-22T12:02:08.642Z")}
{ "_id" : "148404922864202083547392254", "account" : "3600", "amount" : 200, "date" : ISODate("2017-02-02T12:02:08.642Z")}
{ "_id" : "148404972155502083547392254", "account" : "3600", "amount" : 30, "date" : ISODate("2017-02-7T12:02:08.642Z")}
{ "_id" : "148404972864202122254732254", "account" : "3600", "amount" : 10, "date" : ISODate("2017-02-10T12:02:08.642Z")}
对于 1/1/2017 - 10/10/2017
和 1/2/2017 - 10/2/2017
之间的日期范围,输出将如下所示:
- 1/1/2017 - 10/1/2017 - 计数=3,金额总和:170
- 10/2/2017 - 15/2/2017 - 计数=2,金额总和:40
是否可以使用如此不同的日期范围?代码将在 Java 中,但作为 mongo 中的示例,有人可以帮助我吗?
一定有比这更优雅的解决方案。无论如何,您可以将其包装到一个函数中并概括与日期相关的参数。
首先,您需要在确定项目进入哪个范围的同时进行投影(注意巨大的 $switch
表达式)。默认情况下,项目进入 'null' 范围。
然后,您过滤掉不符合您的条件(即范围 != null)的结果。
最后一步是按范围对项目进行分组并进行所有需要的计算。
db.items.aggregate([
{ $project : {
amount : true,
account : true,
date : true,
range : {
$switch : {
branches : [
{
case : {
$and : [
{ $gte : [ "$date", ISODate("2017-01-01T00:00:00.000Z") ] },
{ $lt : [ "$date", ISODate("2017-01-10T00:00:00.000Z") ] }
]
},
then : { $concat : [
{ $dateToString: { format: "%d/%m/%Y", date: ISODate("2017-01-01T00:00:00.000Z") } },
{ $literal : " - " },
{ $dateToString: { format: "%d/%m/%Y", date: ISODate("2017-01-10T00:00:00.000Z") } }
] }
},
{
case : {
$and : [
{ $gte : [ "$date", ISODate("2017-02-01T00:00:00.000Z") ] },
{ $lt : [ "$date", ISODate("2017-02-10T00:00:00.000Z") ] }
]
},
then : { $concat : [
{ $dateToString: { format: "%d/%m/%Y", date: ISODate("2017-02-01T00:00:00.000Z") } },
{ $literal : " - " },
{ $dateToString: { format: "%d/%m/%Y", date: ISODate("2017-02-10T00:00:00.000Z") } }
] }
}
],
default : null
}
}
} },
{ $match : { range : { $ne : null } } },
{ $group : {
_id : "$range",
count : { $sum : 1 },
"amount summation" : { $sum : "$amount" }
} }
])
根据您的数据,它将给出以下结果*:
{ "_id" : "01/02/2017 - 10/02/2017", "count" : 2, "amount summation" : 230 }
{ "_id" : "01/01/2017 - 10/01/2017", "count" : 3, "amount summation" : 170 }
*我相信您的问题中几乎没有错别字,这就是数据看起来不同的原因。
我是 MongoDB 的新手,我一直在努力使特定查询正常工作,但运气不佳。
我有一个包含数百万个具有日期和数量的文档的集合,我想获取特定时间段的聚合。
例如,我想获取 1/1/2015 - 15/1/2015
和 1/2/2015 - 15/2/2015
样本集是
{ "_id" : "148404972864202083547392254", "account" : "3600", "amount" : 50, "date" : ISODate("2017-01-01T12:02:08.642Z")}
{ "_id" : "148404972864202085437392254", "account" : "3600", "amount" : 50, "date" : ISODate("2017-01-03T12:02:08.642Z")}
{ "_id" : "148404372864202083547392254", "account" : "3600", "amount" : 70, "date" : ISODate("2017-01-09T12:02:08.642Z")}
{ "_id" : "148404972864202083547342254", "account" : "3600", "amount" : 150, "date" : ISODate("2017-01-22T12:02:08.642Z")}
{ "_id" : "148404922864202083547392254", "account" : "3600", "amount" : 200, "date" : ISODate("2017-02-02T12:02:08.642Z")}
{ "_id" : "148404972155502083547392254", "account" : "3600", "amount" : 30, "date" : ISODate("2017-02-7T12:02:08.642Z")}
{ "_id" : "148404972864202122254732254", "account" : "3600", "amount" : 10, "date" : ISODate("2017-02-10T12:02:08.642Z")}
对于 1/1/2017 - 10/10/2017
和 1/2/2017 - 10/2/2017
之间的日期范围,输出将如下所示:
- 1/1/2017 - 10/1/2017 - 计数=3,金额总和:170
- 10/2/2017 - 15/2/2017 - 计数=2,金额总和:40
是否可以使用如此不同的日期范围?代码将在 Java 中,但作为 mongo 中的示例,有人可以帮助我吗?
一定有比这更优雅的解决方案。无论如何,您可以将其包装到一个函数中并概括与日期相关的参数。
首先,您需要在确定项目进入哪个范围的同时进行投影(注意巨大的 $switch
表达式)。默认情况下,项目进入 'null' 范围。
然后,您过滤掉不符合您的条件(即范围 != null)的结果。
最后一步是按范围对项目进行分组并进行所有需要的计算。
db.items.aggregate([
{ $project : {
amount : true,
account : true,
date : true,
range : {
$switch : {
branches : [
{
case : {
$and : [
{ $gte : [ "$date", ISODate("2017-01-01T00:00:00.000Z") ] },
{ $lt : [ "$date", ISODate("2017-01-10T00:00:00.000Z") ] }
]
},
then : { $concat : [
{ $dateToString: { format: "%d/%m/%Y", date: ISODate("2017-01-01T00:00:00.000Z") } },
{ $literal : " - " },
{ $dateToString: { format: "%d/%m/%Y", date: ISODate("2017-01-10T00:00:00.000Z") } }
] }
},
{
case : {
$and : [
{ $gte : [ "$date", ISODate("2017-02-01T00:00:00.000Z") ] },
{ $lt : [ "$date", ISODate("2017-02-10T00:00:00.000Z") ] }
]
},
then : { $concat : [
{ $dateToString: { format: "%d/%m/%Y", date: ISODate("2017-02-01T00:00:00.000Z") } },
{ $literal : " - " },
{ $dateToString: { format: "%d/%m/%Y", date: ISODate("2017-02-10T00:00:00.000Z") } }
] }
}
],
default : null
}
}
} },
{ $match : { range : { $ne : null } } },
{ $group : {
_id : "$range",
count : { $sum : 1 },
"amount summation" : { $sum : "$amount" }
} }
])
根据您的数据,它将给出以下结果*:
{ "_id" : "01/02/2017 - 10/02/2017", "count" : 2, "amount summation" : 230 }
{ "_id" : "01/01/2017 - 10/01/2017", "count" : 3, "amount summation" : 170 }
*我相信您的问题中几乎没有错别字,这就是数据看起来不同的原因。