Вы работаете в ограничение яровой Монго в том, что вы можете сделать для расчета поля в одной $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" }
}}
Конечно, чтобы использовать этот вид структуры с пружинно-Монго вам нужна собственная реализация операции агрегации этап, который может занять определенное 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, но округляется до текущей даты.
Это, как правило, намного полезнее, чем извлечение деталей через date aggregation operators, а также работает немного короче кода, особенно при настройке времени с UTC, как вы здесь делаете.
Хотя в строительство из $group
здесь немного более лаконично, чем вспомогательные функции яровых Монго пытаемся избежать, это намного более эффективной, в конце концов, чем запуска отдельного $project
сцены, чтобы преобразовать значения полей, которые вы на самом деле, только хочу на этапе $group
.
Большое спасибо за ответ, и спасибо, что потратили это время, чтобы объяснить ограничение монго и обходное решение! Я попробую этот подход – Thiesen
Этот ответ скалы! – nurgasemetey