Ваш запрос может Исходный был лучше написано. Предположительно, вы хотите группировать результаты по «день», а также настраивать с UTC на локальную временную зону. Обычно лучше просто придерживаться даты математике, а не смеси в date aggregation operators в таком случае, а также это означает, что $project
здесь не требуется, и вы можете просто пойти прямо к $group
:
db.log.aggregate([
{ "$match": {
"ts": {
"$gte": ISODate("2015-07-31T18:30:00.000Z"),
"$lt": ISODate("2015-08-01T18:30:00.000Z")
},
"dup": { "$exists": false }
}},
{ "$group": {
"_id": {
"$add": [
{ "$subtract": [
{ "$subtract": [
{ "$add": [ "$ts", 5.5*1000*60*60 ] },
new Date(0)
]},
{ "$mod": [
{ "$subtract": [
{ "$add": [ "$ts", 5.5*1000*60*60 ] },
new Date(0)
]},
1000*60*60*24
]}
]},
new Date(0)
]
},
"count": { "$sum": 1 }
}}
])
Обратите внимание на дополнительные Date(0)
заявления. Это «эпоха» и точно так же, как при $add
числовое значение до даты, вы получаете тип Date
в обратном порядке, когда вы получаете $subtract
, вы получаете целочисленное значение. Поэтому исправление путем добавления «эпохи» делает все снова Date
.
Следовательно, "дата математике" используется везде, чтобы "круглый" в "день":
(1000 millseconds * 60 секунд * 60 минут * 24 часа)
И оператор modulo $mod
выдает оставшуюся часть этой суммы, которая вычитается из текущего значения даты, чтобы перейти к «округленной» дате.
Все сделано в $group
и эффективно, а также:
Переводя на Java просто следуя те же отступы:
Date startdate = new DateTime(2015, 7, 31, 18, 30, 0, DateTimeZone.UTC).toDate();
Date enddate = new DateTime(2015, 8, 1, 18, 30, 0, DateTimeZone.UTC).toDate();
DBObject query = QueryBuilder.start()
.put("ts").greaterThanEquals(startdate)
.lessThan(enddate)
.and("dup").exists(false).get();
DBObject match = new BasicDBObject("$match",query);
DBObject group = new BasicDBObject("$group",
new BasicDBObject("_id",
new BasicDBObject(
"$add", Arrays.asList(
new BasicDBObject(
"$subtract", Arrays.asList(
new BasicDBObject(
"$subtract", Arrays.asList(
new BasicDBObject(
"$add",Arrays.asList("$ts", 5.5*1000*60*60)
),
new Date(0)
)
),
new BasicDBObject(
"$mod", Arrays.asList(
new BasicDBObject(
"$subtract", Arrays.asList(
new BasicDBObject(
"$add",Arrays.asList("$ts", 5.5*1000*60*60)
),
new Date(0)
)
),
1000*60*60*24
)
)
)
),
new Date(0)
)
)
)
.append("count", new BasicDBObject("$sum",1))
);
AggregationOutput output = collection.aggregate(Arrays.asList(match, group));
for (DBObject result : output.results()) {
System.out.println(result);
}
Также обратите внимание, что ваша «настройка timezeone» здесь предполагая 5,5 часа «за» UTC, который, надеюсь, верен. Если вы имеете в виду «после» или «положительно», то эта операция является «вычитанием», а не дополнением для корректировки часов UTC до нескольких дней.
Итак, все хорошо, и ваши ключи группировки являются реальными и не являются составными значениями, возвращаемыми операторами агрегирования даты.
я попробовал с этим кодом, но его не работал –
ли вы хотите помочь или нет? Затем 1-й, пожалуйста, поймите, что такое форматирование кода, и прекратите отменять ревизии, которые пытаются очистить ваш беспорядок. 2-й «Не работает» не вопрос. Что не работает? Учитывая, что это произошло в двух частях, я могу предположить, что вы пытаетесь перевести свой запрос на Java, и это не то же самое. –