Группировка по интервалу времени между окном времени - PullRequest
0 голосов
/ 21 февраля 2019

У меня следующая структура документа:

{  
   "_id":"5c59c35d8610f702d00e6f70",
   "ipAddress":"50.116.14.48",
   "startTime":"2018-02-06T12:01:59.000Z",
   "endTime":"2018-02-06T12:31:00.000Z", 
}

Я хотел бы иметь возможность группировать события в течение 15 минут.Например;Учитывая структуру документа, приведенного выше, я бы предположил, что этот документ будет считаться вхождением как 0-15 минут, 15-30 минут, так и 30-45 минут.

Результат будет выглядеть примерно так:

[  
   {  
      "occurrences":1,
      "startWindow":"2018-02-06T12:00:00.000Z",
      "endWindow":"2018-02-06T12:15:00.000Z"
   },
   {  
      "occurrences":1,
      "startWindow":"2018-02-06T12:15:01.000Z",
      "endWindow":"2018-02-06T12:30:00.000Z"
   },
   {  
      "occurrences":1,
      "startWindow":"2018-02-06T12:30:01.000Z",
      "endWindow":"2018-02-06T12:45:00.000Z"
   }
]

Я видел много примеров, которые группируют только по одной дате на интервале, но как насчет ситуации, когда у документа есть интервал времени?

Как вы строите эту агрегацию?

Ответы [ 2 ]

0 голосов
/ 21 февраля 2019

Помимо математики времени Микла, вам нужно использовать $ range , чтобы «распределить» документ по всем «окнам» между началом и концом:

db.col.aggregate([
    { $addFields: {
        // an array of 15 min intervals between startTime and endTime
        window: { $range: [ 
            { $floor: { $divide: [ { $toLong: { $toDate: "$startTime" } }, 900000 ] }  }, 
            { $ceil: { $divide: [ { $toLong: { $toDate: "$endTime" } }, 900000 ] }  }
        ] }
    } },
    // 1 document per interval
    { $unwind: "$window" },
    // group by interval
    { $group: {
        _id: "$window",
        occurrences: { $sum: 1 }
    }},
    // to match expected order
    {$sort: {_id:1}},
    // calculate window boundaries
    { $project: {
        _id: 0,
        occurrences: 1,
        startWindow: { $toDate: { $add: [ { $multiply: [ "$_id", 900000 ] }, 1000 ] } },
        endWindow: { $toDate: { $multiply: [ { $add: [ "$_id", 1 ] }, 900000 ] } }        
    } }
])
0 голосов
/ 21 февраля 2019

Легко, если вы можете работать за миллисекунды вместо строк.Чтобы преобразовать ваши startTime и endTime в количество миллисекунд, вы можете использовать операторы $ toDate и $ toLong (MongoDB 4.0 или новее).

TheФормула «классифицировать» ваш диапазон дат по 15 минутам также довольно проста: 15 минут равно 900000 миллисекунд, поэтому вы можете использовать $ mod , чтобы получить значение, которое должно быть $ subtract -ed от исходной даты.

Затем из каждого документа вы можете сгенерировать два документа (для startDate и endDate), используя $ unwind и затем $ group им.

db.col.aggregate([
    {
        $project: {
            startTime: { $toLong: { $toDate: "$startTime" } },
            endTime: { $toLong: { $toDate: "$endTime" } }
        }
    },
    {
        $project: {
            ranges: [
                { 
                    start: { $subtract: [ "$startTime", { $mod: [ "$startTime", 900000 ] } ] },
                    end: { $add: [ { $subtract: [ "$startTime", { $mod: [ "$startTime", 900000 ] } ] }, 900000 ] }
                },
                { 
                    start: { $subtract: [ "$endTime", { $mod: [ "$endTime", 900000 ] } ] },
                    end: { $add: [ { $subtract: [ "$endTime", { $mod: [ "$endTime", 900000 ] } ] }, 900000 ] }
                }
            ]
        }
    },
    {
        $unwind: "$ranges"
    },
    {
        $group: {
            _id: "$ranges",
            count: { $sum: 1 }
        }
    },
    {
        $project: {
            _id: 0,
            occurences: "$count",
            startWindow: { $toString: { $toDate: "$_id.start" } },
            endWindow: { $toString: { $toDate: "$_id.end" } }
        }
    }
])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...