Группа проектов агрегации По извлеченным дням, месяцам и годам с данными 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
этап в любом случае.