Подтвердить что ты не робот

Групповой результат на 15 минут времени в MongoDb

У меня есть коллекция "status", подобная этой strcture -

{
    _id: ObjectId("545a0b63b03dbcd1238b4567"),
    status: 1004,
    comment: "Rem dolor ipsam placeat omnis non. Aspernatur nobis qui nisi similique.",
    created_at: ISODate("2014-11-05T11:34:59.804Z")
},
{
    _id: ObjectId("545a0b66b03dbcd1238b4568"),
    status: 1001,
    comment: "Sint et eos vero ipsa voluptatem harum. Hic unde voluptatibus et blanditiis quod modi.",
    created_at: ISODate("2014-11-05T11:35:02.814Z")
}
....
....

Мне нужно получить результат, сгруппированный на 15-минутный интервал из этой коллекции.

4b9b3361

Ответ 1

Есть несколько способов сделать это.

Первый - с Операторы агрегирования даты, которые позволяют вам анализировать значения даты в документах. В частности, для "группировки" в качестве основного намерения:

db.collection.aggregate([
    { "$group": {
        "_id": {
            "year": { "$year": "$created_at" },
            "dayOfYear": { "$dayOfYear": "$created_at" },
            "interval": {
                "$subtract": [ 
                    { "$minute": "$created_at" },
                    { "$mod": [{ "$minute": "$created_at"}, 15] }
                ]
            }
        }},
        "count": { "$sum": 1 }
    }}
])

Второй способ заключается в использовании небольшого трюка, когда объект даты вычитается (или другая прямая математическая операция) из другого объекта даты, тогда результат представляет собой числовое значение, представляющее миллисекунду временной метки времени между этими двумя объектами. Таким образом, просто используя дату эпохи, вы получаете представление в миллисекундах эпохи. Затем используйте математику даты для интервала:

db.collection.aggregate([
    { "$group": {
        "_id": {
            "$subtract": [
                { "$subtract": [ "$current_date", new Date("1970-01-01") ] },
                { "$mod": [ 
                    { "$subtract": [ "$current_date", new Date("1970-01-01") ] },
                    1000 * 60 * 15
                ]}
            ]
        },
        "count": { "$sum": 1 }
    }}
])

Таким образом, это зависит от того, какой формат вывода вы хотите использовать для интервала группировки. Оба они в основном представляют одно и то же и имеют достаточные данные для повторной конструкции в качестве объекта "даты" в вашем коде.

После группировки _id вы можете поместить все, что захотите, в "оператор группировки". Я просто использую основной пример "count" вместо любого реального заявления от вас непосредственно о том, что вы действительно хотите сделать.

Ответ 2

Мне нравится другой ответ здесь, и в основном для использования математики даты вместо операторов даты агрегации, которые, хотя и полезны, также могут быть немного неясными.

Единственное, что я хочу добавить здесь, это то, что вы также можете вернуть объект Date из структуры агрегации этим подходом, в отличие от "числовой" метки времени. Это просто небольшая дополнительная математика на тех же принципах, используя $add:

db.collection.aggregate([
    { "$group": {
        "_id": {
            "$add": [
                { "$subtract": [
                    { "$subtract": [ "$current_date", new Date(0) ] },
                    { "$mod": [ 
                        { "$subtract": [ "$current_date", new Date(0) ] },
                        1000 * 60 * 15
                    ]}
                ] },
                new Date(0)
            ]
        },
        "count": { "$sum": 1 }
    }}
])

Контексты Date(0) в JavaScript здесь представляют собой ту же самую "эпоху" в более короткой форме, так как 0 миллисекунд с эпохи - это эпоха. Но главное, что когда "добавление" к другому объекту даты BSON выполняется с числовым идентификатором, тогда обратное к описанному условию является истинным, и конечный результат на самом деле теперь является Date.

Все драйверы возвращают родной тип Date на свой язык с помощью этого подхода.

Ответ 3

Немного красивее для mongo db.version() < 3.0

db.collection.aggregate([
    {$match: {created_at:{$exists:1}}},
    {$group: {
        _id: {$add:[
            {$dayOfYear: "$created_at" },
            {$multiply: [{$year: "$created_at"}, 1000]}
        ]},
        count: {$sum: 1 }
    }},
    {$sort:{_id:-1}}
])

Ответ 4

Еще один полезный способ:

db.collection.aggregate([
  {$group: {
    _id: { 
      overallTime: { 
        $dateToString: { format: "%Y-%m-%dT%H", date: "$created_at" } 
      },
      interval: { $trunc: { $divide: [{ $minute: "$created_at" }, 15 ]}}
    },
  }},
])

И проще для минут, часов, дней:

var format = "%Y-%m-%dT%H:%M"; // 1 min
var format = "%Y-%m-%dT%H"; // 1 hour
var format = "%Y-%m-%d"; // 1 day

db.collection.aggregate([
  {$group: {
    _id: { $dateToString: { format: format, date: "$created_at" } },
  }},
])