Следующая агрегация вычисляет сеансы и возвращает сеанс start и end раз (для каждого сеанса). Обратите внимание, что я преобразовал поле строки access_time
в объект date
для упрощения расчетов.
const FIVE_MINS = 5 * 60 * 1000 // time in milliseconds
db.collection.aggregate( [
{
$sort: { account: 1, access_time: 1 }
},
{
$group: {
_id: "$account",
access_times: { $push: { $toDate: "$access_time" } }
}
},
{
$addFields: {
sessions: {
$reduce: {
input: "$access_times",
initialValue: {
first: { $arrayElemAt: [ "$access_times", 0 ] },
prev: { $arrayElemAt: [ "$access_times", 0 ] },
sessions: []
},
in: {
$cond: [ { $gt: [ { $subtract: [ "$$this", "$$value.prev" ] }, FIVE_MINS ] },
{
first: "$$this",
prev: "$$this",
sessions: { $concatArrays: [ "$$value.sessions" ,
[ { start: "$$value.first", end: "$$value.prev" } ]
] }
},
{
first: "$$value.first",
prev: "$$this",
sessions: "$$value.sessions"
}
]
}
}
}
}
},
{
$project: {
_id: 0,
account: "$_id",
access_times: 1,
sessions: {
$concatArrays: [ "$sessions.sessions", [ { start: "$sessions.first", end: "$sessions.prev" } ] ]
}
}
}
] )
Вывод (с использованием опубликованных данных):
{
"access_times" : [
ISODate("2020-04-04T12:27:00Z"),
ISODate("2020-04-04T12:30:21Z"),
ISODate("2020-04-04T12:31:20Z"),
ISODate("2020-04-04T12:40:20Z"),
ISODate("2020-04-04T12:41:25Z"),
ISODate("2020-04-04T12:42:30Z")
],
"account" : "aaaa",
"sessions" : [
{
"start" : ISODate("2020-04-04T12:27:00Z"),
"end" : ISODate("2020-04-04T12:31:20Z")
},
{
"start" : ISODate("2020-04-04T12:40:20Z"),
"end" : ISODate("2020-04-04T12:42:30Z")
}
]
}