Объединение MongoDB в PHP, добавление секунд к дате/времени

У меня есть агрегат MongoDB в PHP, определенный как:

$results = $c->aggregate(array(
    array(
      '$project' => array(
          'year' => array('$year' => array('$add' => array('$executed.getTime()', 3600))),
          'month' => array('$month' => array('$add' => array('$executed.getTime()', 3600))),
          'day' => array('$dayOfMonth' => array('$add' => array('$executed.getTime()', 3600)))
      ),
    ),
    array(
      '$group' => array(
          '_id' => array('year' => '$year', 'month' => '$month', 'day' => '$day'),
          'count' => array('$sum' => 1)
      ),
    ),
    array(
      '$sort' => array(
          '_id' => 1
      ),
    ),
    array(
      '$limit' => 30
    )
));

Проблема в том, что агрегатная функция $add в $project не работает.

 exception: the $year operator does not accept an object as an operand

Как правильно добавить произвольное количество секунд в поле даты/времени $executed?

Спасибо.


person Justin    schedule 28.01.2013    source источник
comment
Не работает - каким образом?   -  person Joachim Isaksson    schedule 28.01.2013
comment
Массив ( [errmsg] =› исключение: оператор $year не принимает объект в качестве операнда [code] =› 16021 [ok] =› 0 )   -  person Justin    schedule 28.01.2013
comment
Является ли $executed полем в вашем документе или вы ожидаете, что оно будет существовать как константа, но не существует? В любом случае вы не можете использовать такие функции в совокупности   -  person Sammaye    schedule 28.01.2013
comment
$executed — это имя поля, дата/время MongoDB BSON.   -  person Justin    schedule 28.01.2013
comment
Хорошо. Кажется, $add еще не поддерживает даты. Хм, вам нужно найти другой способ обойти это.   -  person Sammaye    schedule 29.01.2013
comment
Да, конвейер агрегации имеет очень ограниченную поддержку манипулирования датами. Для немного другого подхода взгляните на stackoverflow.com/questions/14555140/ Вы в одном классе? Надеюсь, это не финальная встреча :)   -  person mjhm    schedule 29.01.2013
comment
Агрегаты MongoDB очень разочаровывают. Мне нужно полностью переделать это.   -  person Justin    schedule 29.01.2013


Ответы (1)


Проблема, которую вы видите, — это ошибка в MongoDB, о которой я сообщил в SERVER-9289. Обходной путь для этого влечет за собой перенос аргумента оператора даты в массив, как в следующем примере оболочки:

> db.foo.drop()

> db.foo.insert({x:ISODate()})

> db.foo.aggregate({$project: {x:1, y: {$year: {$add:['$x',1000]}}}})
Error: Printing Stack Trace
    at printStackTrace (src/mongo/shell/utils.js:37:7)
    at DBCollection.aggregate (src/mongo/shell/collection.js:897:1)
    at (shell):1:8
Mon Apr  8 18:15:15.198 JavaScript execution failed: aggregate failed: {
    "errmsg" : "exception: the $year operator does not accept an object as an operand",
    "code" : 16021,
    "ok" : 0
} at src/mongo/shell/collection.js:L898

> db.foo.aggregate({$project: {x:1, y: {$year: [{$add:['$x',1000]}]}}})
{
    "result" : [
        {
            "_id" : ObjectId("516341333512acfb2d33f156"),
            "x" : ISODate("2013-04-08T22:14:11.665Z"),
            "y" : 2013
        }
    ],
    "ok" : 1
}

Перенести это на PHP должно быть тривиально.

Сказав это, ваш исходный код содержит ошибку в ссылке на $executed. Согласно документации $project, вы можете обращаться к полям в документ BSON по имени (или пунктирный путь к полю в объектах/массивах), но нет поддержки для вызова методов JavaScript для этих полей. В соответствии с этим конвейер агрегации работает с необработанными документами BSON, поэтому эти типы никогда не транслируются в их представления JavaScript в ходе конвейера (например, дата BSON никогда не становится ISODate).

К счастью, в MongoDB 2.4 даже не нужно вызывать $executed.getTime(). SERVER-6239 улучшена поддержка обработки даты BSON в $add и $subtract. Вы можете увидеть этот билет для получения более подробной информации, например ожидаемого результата для вычитания двух дат или добавления даты и числа.

person jmikola    schedule 08.04.2013