Группа проектов агрегации По извлеченным дням, месяцам и годам с данными Spring

Чтобы быть прямым, как мне это сделать:

group._id = { 
    year: { $year : [{ $subtract: [ "$timestamp", 25200000 ]}] }, 
    month: { $month : [{ $subtract: [ "$timestamp", 25200000 ]}] }, 
    day: { $dayOfMonth : [{ $subtract: [ "$timestamp", 25200000 ]}] }
};

с пружиной Data

Я попробовал это уже и некоторые другие формы и не были успешными

Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(c),
                Aggregation.project("programa", "custo", "duracao", "dataHora")
                    .andExpression("dataHora").minus(25200000).extractDayOfMonth().as("dia")
                    .andExpression("dataHora").minus(25200000).extractMonth().as("mes")
                    .andExpression("dataHora").minus(25200000).extractYear().as("ano"),
                Aggregation.group("programa", "ano", "mes", "dia")
                    .count().as("count")
                    .sum("custo").as("valorTotal")
                    .sum("duracao").as("duracaoTotal")
                    .first("dataHora").as("dataHora"),
                Aggregation.sort(Direction.ASC, "dataHora")
        );

Мне нужно сгруппировать по дням, месяцам и годам в mongodb, иначе мне нужно будет преобразовать все эти сгруппированные данные в код.

заранее спасибо

1 ответ

Решение

Вы сталкиваетесь с ограничением Spring Mongo в том, что вы можете сделать для полевых расчетов в одном $project этап, и действительно, вы, вероятно, уже пишете как отдельный $project так как вы обнаружите, что вы не можете проецировать пользовательские именованные поля непосредственно в $group_id в настоящее время тоже.

Так что вам лучше оставить все это в $group, а также используя другой метод для округления ваших скорректированных дат по местному времени.

Лучший способ написать свой $group поэтому будет:

{ "$group": {
  "_id": {
    "programa": "$programa",
    "dataHora": {
      "$add": [
        { "$subtract": [
          { "$subtract": [{ "$subtract": ["$dataHora", new Date(0)] }, 25200000 ] },
          { "$mod": [
            { "$subtract": [{ "$subtract": ["$dataHora", new Date(0)] }, 25200000 ] },
            1000 * 60 * 60 * 24
          ]}
        ]},
        new Date(0)
      ]
    }
  },
  "count": { "$sum": 1 },
  "valorTotal": { "$sum": "$custo" },
  "duracaoTotal": { "$sum": "$duracao" },
  "dataHora": { "$first": "$dataHora" }
}}

Конечно, чтобы использовать такую ​​структуру с spring-mongo, вам нужна индивидуальная реализация операции этапа агрегации, которая может принимать определенные DBObject:

public class CustomGroupOperation implements AggregationOperation {
    private DBObject operation;

    public CustomGroupOperation (DBObject operation) {
        this.operation = operation;
    }

    @Override
    public DBObject toDBObject(AggregationOperationContext context) {
        return context.getMappedObject(operation);
    }
}

Который вы затем используете в контексте, как это:

    Aggregation aggregation = Aggregation.newAggregation(
            Aggregation.match(c),
            new CustomGroupOperation(
                new BasicDBObject("$group",
                    new BasicDBObject("_id",
                        new BasicDBObject("programa","$programa")
                            .append("dataHora",
                                new BasicDBObject("$add",Arrays.asList(
                                    new BasicDBObject("$subtract",Arrays.asList(
                                        new BasicDBObject("$subtract",Arrays.asList(
                                            new BasicDBObject("$subtract",Arrays.asList(
                                                "$dataHora", new Date(0)
                                            )),
                                            25200000
                                        )),
                                        new BasicDBObject("$mod",Arrays.asList(
                                            new BasicDBObject("$subtract",Arrays.asList(
                                                new BasicDBObject("$subtract",Arrays.asList(
                                                    "$dataHora", new Date(0)
                                                )),
                                                25200000
                                            )),
                                            1000 * 60 * 60 * 24
                                        ))
                                    )),
                                    new Date(0)
                                ))
                            )
                    )
                    .append("count",new BasicDBObject("$sum",1))
                    .append("valorTotal",new BasicDBObject("$sum","$custo"))
                    .append("duracaoTotal",new BasicDBObject("$sum","$duracao"))
                    .append("dataHora",new BasicDBObject("$first","$dataHora"))
                )
            ),
            Aggregation.sort(Direction.ASC,"_id.dataHora")
    );

Поскольку пользовательский класс абстрагируется от того же базового класса, который используется встроенными вспомогательными методами, его можно использовать вместе с ними, как показано.

Как работает базовый процесс с математикой даты, когда вы $subtract один объект BSON Date от другого, тогда результатом является разность в миллисекундах, и в этом случае от даты эпохи ( Date(0)), которая просто извлекает значение в миллисекундах. Это позволяет выполнять математические вычисления для округления до текущего значения даты по модулю ($mod) от количества миллисекунд за один день.

Как бы вы ни старались, когда вы $addэто значение в миллисекундах для объекта даты BSON, возвращаемое значение снова является датой BSON. Таким образом, добавление к объекту, представляющему эпоху, возвращает новый объект Date, но округленный до текущей даты.

Это обычно намного полезнее, чем извлечение частей с помощью операторов агрегации дат, а также работает немного короче кода, особенно при настройке времени из UTC, как вы делаете здесь.

Хотя строительство $group здесь немного более кратко, чем пытаются избежать вспомогательные функции пружинного монго, в конечном итоге это намного эффективнее, чем запуск отдельного $project этап для преобразования значений поля, которые вы действительно хотите только в $group этап в любом случае.

Другие вопросы по тегам