Pentaho Report Designer MongoDB, группировка по отметкам времени эпохи

Мой первый пост на StackOverflow!

У меня есть коллекция MongoDB под названием user_sessions — один документ выглядит так:

{
    "_id" : ObjectId("53e352bbed3e4af00d8b459a"),
    "active_date" : 1407406779727,
    "auth_token" : "WObDF9KO6n1V34lgjlFIoXoiEmOH9CM8",
    "device_token" : "3474ac2d5aa9c7dc933bd4548c2dd6ea3d8a9592dad1c1a807c06ac2c8459205",
    "device_type" : "1",
    "end_time" : "",
    "sessionid" : "",
    "start_time" : 1407406779727,
    "userid" : "53e352bbed3e4af00d8b4599"
}

Я пытаюсь создать отчет с помощью конструктора отчетов Pentaho (5.1). Мне удалось вывести общее количество пользовательских сеансов с помощью этого запроса:

[
      { $group: { _id: null, count: { $sum: 1 } } }
]

что здорово.

Однако я хотел бы также показать количество сеансов по дате.

Когда я запускаю этот PHP-скрипт для этой коллекции (используя драйвер PHP Mongo):

$connection = new Mongo("mongodb://$dbhost");
$c_us = $db->user_session;
$cursor = $c_us->find();
foreach ( $cursor as $document ) {
    echo "<br/>UserID: " . $document['userid'] . ", StartTime: ";
    $epoch = $document['start_time'];
    echo date('Y-m-d',$epoch/1000); 
}

Я получаю этот вывод:

UserID: 53dfa1a7ed3e4aef0d8b456b, StartTime: 2014-08-05
UserID: 53e075deed3e4af00d8b4570, StartTime: 2014-08-05
UserID: 53e079c9ed3e4af00d8b4573, StartTime: 2014-08-05
UserID: 53e07f8ded3e4aef0d8b4580, StartTime: 2014-08-05
UserID: 53e081f9ed3e4aef0d8b4583, StartTime: 2014-08-05
UserID: 53e352bbed3e4af00d8b4599, StartTime: 2014-08-07
UserID: 53e9fb9eed3e4af00d8b45a3, StartTime: 2014-08-12
UserID: 53f215f6ed3e4aef0d8b45a3, StartTime: 2014-08-19
UserID: 53f3eeb7ed3e4aef0d8b45a7, StartTime: 2014-08-20
UserID: 54083e94ed3e4af00d8b45b0, StartTime: 2014-09-04
UserID: 5412cd29ed3e4aef0d8b45bc, StartTime: 2014-09-12
UserID: 54175625ed3e4aef0d8b45c0, StartTime: 2014-09-16
UserID: 54351b7ced3e4af00d8b45ff, StartTime: 2014-10-08
UserID: 5444f1dced3e4a56718b45bb, StartTime: 2014-10-20
UserID: 54475d48ed3e4af00d8b4628, StartTime: 2014-10-22
UserID: 5449cc77ed3e4a79638b4592, StartTime: 2014-10-24
UserID: 53e3c875ed3e4af00d8b459d, StartTime: 2014-10-24
UserID: 544f6bb7ed3e4af00d8b464a, StartTime: 2014-10-28
UserID: 544de95aed3e4a56718b45f2, StartTime: 2014-10-31
UserID: 545b125c4a4ddd30048b4567, StartTime: 2014-11-06

Фантастика!

Но как я могу подсчитать сеансы по дате (и месяцу/дате)?

Итак, для вышеизложенного мне нужны такие отчеты:

2014-08-05    5
2014-08-07    1
.
.
.
2014-10-24    2

так далее

а также

Month/Year     Count
Aug 2014       9
Sep 2014       3
Oct 2014       7
Nov 2014       1

Учитывая схему user_session, как я могу преобразовать время эпохи в start_time в месяц/год и подсчитать?

Мое исследование ключевых слов не дало мне ничего, что я мог бы попробовать.

Я в растерянности. Что я должен вводить в качестве условия поиска? Может ли кто-нибудь дать мне несколько советов?

Я был бы очень признателен.

Спасибо

Брэд


comment
Извините, я не очень хорошо знаком с pentaho или PHP, но у MongoDB есть несколько отличных агрегаторов дат, которые вы можете использовать, они описаны здесь: docs.mongodb.org/manual/reference/operator/aggregation/   -  person Randall Hunt    schedule 06.11.2014
comment
@ранман! Спасибо! Я перешел по ссылке $month и оказался здесь [ссылка]docs.mongodb.org/manual/reference/operator/aggregation/month/, и я изменил их пример, но получил эту ошибку: `Ошибка (печать трассировки стека) @: 0 () @ src/mongo /shell/utils.js:37 ([object Array])@src/mongo/shell/collection.js:866 @(shell):15 необработанное исключение: сбой объединения: { errmsg : исключение: невозможно преобразовать из типа BSON NumberDouble to Date, код: 16006, ok: 0 } `   -  person bradzo    schedule 06.11.2014


Ответы (1)


Для справки: есть операторы агрегирования дат, которые вы можете использовать для анализа таких вещей, как $year и < a href="http://docs.mongodb.org/manual/reference/operator/aggregation/month/" rel="nofollow">$month и $dayOfMonth в ключи группировки для платформы агрегации следующим образом:

db.collection.aggregate([
   { "$group": {
       "_id": {
           "year": { "$year": "$start_time" },
           "month": { "$month": "$start_time" },
           "day": { "$dayOfMonth": "$start_time" }
       },
       "count": { "$sum": 1 }
   }}
])

Но если вас устраивают значения «отметка времени эпохи», вы всегда можете использовать этот базовый прием сопоставления с объектами «дата» и «математикой даты» в целом, чтобы получить отметку времени эпохи, округленную до требуемого значения:

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

Основная хитрость заключается в том, что когда вы «вычитаете» или выполняете другие подобные математические операции из одного объекта «дата» в другой, результатом является «разница в миллисекундах» от объектов в виде целого числа. В приведенном примере (1000 * 60 * 60 * 24) это равно одному дню по времени, а по модулю значение округляется до текущего дня.

Это дает альтернативный подход к операторам агрегирования дат, когда может потребоваться фактическое получение значения «отметка времени».

Поскольку все входные данные для конвейера агрегации будут "сериализованы" при отправке, все допустимые "объекты данных" на любом данном языке, поддерживаемом драйвером, будут иметь правильное входное значение. Мы просто используем здесь дату «эпохи», чтобы «преобразовать» значение объекта даты, присутствующее в коллекции, в целое число.

Это зависит от того, что вы предпочитаете в качестве вывода. Некоторые люди предпочитают "целочисленную" форму как легкое приведение к новому объекту "дата". Некоторые довольны отдельными полевыми частями, чтобы сделать это.

person Neil Lunn    schedule 06.11.2014
comment
Спасибо @Neil - я попробовал ваш первый код (заменив вашу коллекцию на мою user_session) и получил эту ошибку: неперехваченное исключение: сбой агрегата: { errmsg: исключение: невозможно преобразовать из типа BSON NumberDouble в Date, код: 16006, ok: 0 } и ваш второй пример: неперехваченное исключение: агрегатный сбой: { errmsg: исключение: не могу $вычесть aDate из NumberDouble, код: 16556, ok: 0} - person bradzo; 07.11.2014
comment
@bradzo Это означает, что вы на самом деле не храните типы дат, а просто числовые значения меток времени. Используйте метод second без вычитания из объектов даты, поскольку значения уже должны быть значениями временной метки эпохи. И, возможно, не в миллисекундах, поэтому посмотрите на свои данные и, при желании, отбросьте множитель 1000. - person Neil Lunn; 07.11.2014
comment
#Нил, спасибо - когда я удаляю материал #subtract, я получаю то же, что и в своем исходном посте - просто количество записей, то есть: 20. Я просто не знаю, как преобразовать эту отметку времени эпохи (которая должна be / 1000 в скрипте PHP, чтобы указать правильную дату) в объект даты. Я читал, что это невозможно. Возможно, мне следует использовать сценарий Groovy (помните, что конечный запрос будет выполняться сервером отчетов Pentaho) - спасибо за вашу помощь. - person bradzo; 07.11.2014
comment
@bradzo Как я уже сказал. Ваши данные не относятся к типу даты. Итак, если это не дата и не целое число или двойное число, то это строка. Вы видите здесь проблему? Вам нужно исправить свои данные. - person Neil Lunn; 07.11.2014
comment
да, свяжусь с разработчиками сейчас - дам вам знать, как я пойду, но большое вам спасибо. Я действительно ценю твою помощь. - person bradzo; 07.11.2014