2015-08-31 5 views
0

Я хочу запустить этот запрос mongodb с помощью java-кода.Агрегирование Даты настройки запросов для часового пояса

Запрос:

db.log.aggregate([ 
    { $match : { 
     "ts" : { 
      $gte: ISODate("2015-07-31T18:30:00.000Z"), 
      $lt: ISODate("2015-08-01T18:30:00.000Z") 
     }, 
     "dup": {$exists:false} 
    }}, 
    { $project : { 
     'lts': { 
      '$add': ['$ts',5.5*3600*1000] 
     } 
    }}, 
    { $group : { 
     _id : { 
      day: { $dayOfMonth: "$lts" }, 
      month: { $month: "$lts" }, 
      year: { $year: "$lts" } 
     }, 
     count: { $sum: 1 } 
    }} 
]) 

я попробовал с этим кодом, но его не работали

                    DBObject query = QueryBuilder.start().put("ts").greaterThanEquals(startdate).lessThanEquals(enddate).and("dup").exists(false).get();   
    DBObject match = new BasicDBObject("$match", query); 
    DBObject project=new BasicDBObject("$project", new BasicDBObject("ts",new BasicDBObject("$add",5.5*3600*1000))); 
    DBObject group = new BasicDBObject("$group", new BasicDBObject("_id",new BasicDBObject("day", new BasicDBObject("$dayOfMonth", "$ts")) 
    ).append("count", new Document("$sum", 1))); 

    AggregationOutput output = collection.aggregate(match,group); 

    for (DBObject result : output.results()) { 
     System.out.println(result); 
     } 
+0

я попробовал с этим кодом, но его не работал –

+1

ли вы хотите помочь или нет? Затем 1-й, пожалуйста, поймите, что такое форматирование кода, и прекратите отменять ревизии, которые пытаются очистить ваш беспорядок. 2-й «Не работает» не вопрос. Что не работает? Учитывая, что это произошло в двух частях, я могу предположить, что вы пытаетесь перевести свой запрос на Java, и это не то же самое. –

ответ

2

Ваш запрос может Исходный был лучше написано. Предположительно, вы хотите группировать результаты по «день», а также настраивать с 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 до нескольких дней.

Итак, все хорошо, и ваши ключи группировки являются реальными и не являются составными значениями, возвращаемыми операторами агрегирования даты.

+0

Большое спасибо. Ваше решение отличное. Он отлично работает. Я тоже хочу понять, как я могу это сделать через проекцию в java, если вы можете мне помочь, и это будет так здорово –

0

изменение поля ц на восток 8 часовой пояс:

BasicDBObject addEightHour = new BasicDBObject("$add", Arrays.asList("$ts", 8*1000*60*60)); 
    final BasicDBObject day = new BasicDBObject("$dateToString", new BasicDBObject("format", "\"%Y%m%d\"").append("date", addEightHour)); 

    DBObject groupFields = new BasicDBObject("_id", new BasicDBObject(
      "value", day)); 
    DBObject group = new BasicDBObject("$group", groupFields); 
Смежные вопросы