如何解决在MongoDB中是否可以将具有日期的对象分组汇总为增量间隔?
我目前正在尝试在MongoDB中创建一个聚合管道,以将项目按递增的时间间隔进行分组,但是到目前为止,我仅成功将它们按不相交的时间间隔进行分组。
样本数据:
{
"eventID": "abc","date": ISODate("2020-11-05T12:05:11.790Z"),...........
},{
"eventID": "xyz","date": ISODate("2020-11-05T12:12:11.790Z"),{
"eventID": "klm","date": ISODate("2020-11-05T12:28:11.790Z"),...........
}
当前解决方案:
$group: {
"_id": {
"year": { $year: "$date" },"dayOfYear": { $dayOfYear: "$date" },"hour": { $hour: "$date" },"interval": {
"$subtract": [
{ "$minute": "$date" },{ "$mod": [{ "$minute": "$date"},10 ] }
]
}
},"grouped_data": { "$push": { "eventID": "$eventID","date": "$date" },"count": { $sum: 1 } }
}
将返回以10分钟为间隔的分组数据,但这些数据是不相交的间隔(10分钟的时间窗口不相交)。 例如:
{
"_id": {
"year": 2020,"dayOfYear": "314","hour": 12,"interval": 0,// = interval beginning at minute 0 of 12th hour of the day
},"grouped_data": [{ "eventID": "abc","date": ISODate("2020-11-05T12:05:11.790Z" }],"count": 1
},{
"_id": {
"year": 2020,"interval": 10,// = beginning at minute 10
},"grouped_data": [{ "eventID": "xyz","date": ISODate("2020-11-05T12:12:11.790Z") }],"interval": 20,// = beginning at minute 20
},"grouped_data": [{ "eventID": "klm","date": ISODate("2020-11-05T12:28:11.790Z") }],"count": 1
}
我真正要寻找的是在10分钟内(或所需的任何时间)以增量间隔对它们进行分组。例如:0-9、1-10、2-11等,而不是0-9、10-19、20-29等。
编辑: 此处的最终目标是检查用户定义的间隔长度是否超过了计数阈值。 如果用户问“在10分钟的时间窗口中是否有2个以上的事件?” ,则根据上述示例数据和我当前的解决方案,条件不满足。 (在0-9间隔中发生1个事件,在10-19中发生1个事件)。以递增的间隔,我应该能够发现在10分钟内确实有2个事件,但是在5-14的时间间隔内。例如:
{
"_id": {
*whatever logic for grouping in 10minutes window*
},"grouped_data": [
{ "eventID": "abc","date": ISODate("2020-11-05T12:05:11.790Z") },{ "eventID": "xyz","count": 2
},{
"_id": {
*whatever logic for grouping in 10minutes window*
},"grouped_data": [
{ "eventID": "klm","date": ISODate("2020-11-05T12:28:11.790Z") }]
"count": 1
},
解决方法
对于我来说,尚不清楚您要获得哪个输出,但是此聚合管道使滑动窗口组成为了
db.collection.aggregate([
{
$group: {
_id: null,data: { $push: "$$ROOT" },min_date: { $min: "$date" },max_date: { $max: "$date" }
}
},{
$addFields: {
interval: {
$range: [
{ $toInt: { $divide: [{ $toLong: "$min_date" },1000] } },{ $toInt: { $divide: [{ $toLong: "$max_date" },10 * 60]
}
}
},{
$set: {
interval: {
$map: {
input: "$interval",in: { $toDate: { $multiply: ["$$this",1000] } }
}
}
}
},{ $unwind: "$interval" },{
$project: {
grouped_data: {
$filter: {
input: "$data",cond: {
$and: [
{ $gte: ["$$this.date","$interval"] },{ $lt: ["$$this.date",{ $add: ["$interval",1000 * 60 * 10] }] },]
}
}
},interval: 1
}
}
])
边界由输入数据给定,但是也可以使用修正日期:
db.collection.aggregate([
{ $group: { _id: null,data: { $push: "$$ROOT" } } },{
$addFields: {
interval: {
$range: [
{ $toInt: { $divide: [{ $toLong: ISODate("2020-01-01T00:00:00Z") },{ $toInt: { $divide: [{ $toLong: ISODate("2020-12-31T23:59:59Z") },interval: 1
}
}
])
,
我将尝试回答我自己的问题,也许它将对互联网上的其他人有所帮助。我想出的解决方案基于@Wernfried的答案(谢谢!)。
db.getCollection("events_en").aggregate([
{
$match: { eventID: "XYZ" }
},{
$group: {
_id: null,events: { $push: "$$ROOT" },limit: { $push: { $toDate: { $add: [{ $toLong: "$date" },1000 * 60 * 10] } } }
}
},{ $unwind: "$limit" },{
$project: {
events: {
$filter: {
input: "$events",cond: {
$and: [
{ $lt: ["$$this.date","$limit"] },{ $gte: ["$$this.date",{ $subtract: ["$limit",limit: 1,}
},{
$addFields: {
count: {
$size: "$events"
}
}
}
])
这将根据事件的日期+ 10分钟(或其他时间)为每个事件创建一个限制。然后,它根据该限制过滤事件(现在使用$ unwind:“ $ limit”为每个限制复制事件)。结果是这样的:
{
"_id" : null,"limit" : ISODate("2020-11-05T12:28:27.000+0000"),"events" : [
{
"_id" : 13,"eventID" : "XYZ","date" : ISODate("2020-11-05T12:18:27.000+0000")
},{
"_id" : 63,"date" : ISODate("2020-11-05T12:19:55.000+0000")
},............................
{
"_id" : 90,"date" : ISODate("2020-11-05T12:27:57.000+0000")
}
],"count" : 5
}
{
"_id" : null,"limit" : ISODate("2020-11-05T12:29:55.000+0000"),"events" : [
{
"_id" : 63,{
"_id" : 90,"date" : ISODate("2020-11-05T12:27:57.000+0000")
},{
"_id" : 97,"date" : ISODate("2020-11-05T12:29:36.000+0000")
}
],"count" : 3
}
如您所见,查看每个组的限制和每个组中事件的日期,这些间隔现在是递增的,而不是不相交的。 (事件X可以在多个组中找到,只要它不超过10分钟的时间间隔即可)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。