Агрегат MongoTemplate — группировка по дате

Я пытаюсь создать агрегированный запрос, используя mongotemplate, где есть группировка по дате (например, 2016-03-01) вместо даты и времени (например, 2016-03-01 16:40:12). Операция dateToString существует в документации mongodb, ее можно использовать для извлечения даты из даты и времени с использованием форматирования: https://docs.mongodb.org/manual/reference/operator/aggregation/dateToString/, но я заставляю его работать с mongotemplate - я получаю исключение NullPointerException. (моя версия БД 3.2)

List<AggregationOperation> aggregationOperations = new ArrayList<AggregationOperation>();

aggregationOperations.add(
          Aggregation.project("blabla", ...).
          andExpression("dateToString('%Y-%m-%d',timeCreated).as("date"));

aggregationOperations.add(Aggregation.group("date").sum("blabla").as("blabla"));

AggregationResults<?> aggregationResults = this.mongoTemplate.aggregate(
                        Aggregation.newAggregation(aggregationOperations),
                                    collectionName,
                                    resultClass);

Когда я использую dayOfMonth(timeCreated) для извлечения дня, исключений нет, но я не смог найти и пример того, как заставить это работать с dateToString. Я пробовал без '' для формата даты, и это тоже не сработало...

Это исключение, которое я получаю:

java.lang.NullPointerException
    at org.bson.BasicBSONEncoder._putObjectField(BasicBSONEncoder.java:226)
    at org.bson.BasicBSONEncoder.putObject(BasicBSONEncoder.java:194)
    at org.bson.BasicBSONEncoder._putObjectField(BasicBSONEncoder.java:255)
    at org.bson.BasicBSONEncoder.putObject(BasicBSONEncoder.java:194)
    at org.bson.BasicBSONEncoder._putObjectField(BasicBSONEncoder.java:255)
    at org.bson.BasicBSONEncoder.putObject(BasicBSONEncoder.java:194)
    at org.bson.BasicBSONEncoder._putObjectField(BasicBSONEncoder.java:255)
    at org.bson.BasicBSONEncoder.putIterable(BasicBSONEncoder.java:324)
    at org.bson.BasicBSONEncoder._putObjectField(BasicBSONEncoder.java:263)
    at org.bson.BasicBSONEncoder.putObject(BasicBSONEncoder.java:194)
    at org.bson.BasicBSONEncoder.putObject(BasicBSONEncoder.java:136)
    at com.mongodb.DefaultDBEncoder.writeObject(DefaultDBEncoder.java:36)
    at com.mongodb.OutMessage.putObject(OutMessage.java:289)
    at com.mongodb.OutMessage.writeQuery(OutMessage.java:211)
    at com.mongodb.OutMessage.query(OutMessage.java:86)
    at com.mongodb.DBCollectionImpl.find(DBCollectionImpl.java:81)
    at com.mongodb.DB.command(DB.java:320)
    at com.mongodb.DB.command(DB.java:299)
    at com.mongodb.DB.command(DB.java:374)
    at com.mongodb.DB.command(DB.java:246)
    at org.springframework.data.mongodb.core.MongoTemplate$2.doInDB(MongoTemplate.java:357)
    at org.springframework.data.mongodb.core.MongoTemplate$2.doInDB(MongoTemplate.java:355)
    at org.springframework.data.mongodb.core.MongoTemplate.execute(MongoTemplate.java:442)
    at org.springframework.data.mongodb.core.MongoTemplate.executeCommand(MongoTemplate.java:355)
    at org.springframework.data.mongodb.core.MongoTemplate.aggregate(MongoTemplate.java:1497)
    at org.springframework.data.mongodb.core.MongoTemplate.aggregate(MongoTemplate.java:1432)

ИЗМЕНИТЬ:

В конце концов мы выбрали здесь решение, отличное от того, что было предложено ниже, я пишу его здесь на случай, если кто-то еще сочтет его полезным:

В дополнение к полю «timeCreated», которое содержит дату и время, мы сохранили в документе еще одно поле: «date», которое содержит только дату (как долго).

Например, если "timeCreated" = "2015-12-24 16:36:06.657+02:00", то дата "2015-12-24 00:00:00", и мы сохраняем 1449180000000. Теперь мы можем просто сгруппировать по «дате».


person Ayelet    schedule 03.01.2016    source источник


Ответы (2)


Вы можете сначала попробовать проецировать поля, используя SpEL andExpression в операции проекции, а затем сгруппировать по новым полям в операции группировки:

Aggregation agg = newAggregation(
    project()       
        .andExpression("year(timeCreated)").as("year")
        .andExpression("month(timeCreated)").as("month")
        .andExpression("dayOfMonth(timeCreated)").as("day"),
    group(fields().and("year").and("month").and("day"))     
        .sum("blabla").as("blabla")
);

AggregationResults<BlaBlaModel> result = 
    mongoTemplate.aggregate(agg, collectionName, BlaBlaModel.class);
List<BlaBlaModel> resultList = result.getMappedResults();
person chridam    schedule 03.01.2016
comment
Спасибо, я мог бы это сделать, но кажется намного проще использовать dateToString, за исключением того, что я не знаю, почему он выдает исключение... - person Ayelet; 03.01.2016
comment
@Ayelet Боюсь, что Spring Data MongoDB в настоящее время не поддерживает это, для этого есть открытый билет JIRA здесь - person chridam; 03.01.2016

Вы можете попробовать использовать класс DateOperators.DateToString

aggregationOperations.add(
      Aggregation.project("blabla", ...).
      and(DateOperators.DateToString.dateOf("timeCreated").toString("%Y-%m-%d"));
person rohit    schedule 14.02.2019