Sie sind in eine Begrenzung der Feder Mongo läuft in dem, was Sie für Feldberechnungen in einem einzigen $project
Bühne tun können, und in der Tat werden Sie wahrscheinlich bereits als separate $project
schreiben, da Sie, dass Sie entdecken Namhafte Felder können jetzt auch nicht direkt in einem $group
_id
projiziert werden.
Sie wären also besser dran, alles in der $group
zu halten, sowie eine andere Methode zum Runden Ihrer angepassten Daten auf Ortszeit verwenden.
Der bessere Weg Ihr schreiben $group
daher wäre:
{ "$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" }
}}
Natürlich, diese Art von Struktur zu verwenden, mit Feder mongo Sie Implementierung der Aggregationsstufe Operation eine benutzerdefinierte müssen die DBObject
eine definierte nehmen :
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);
}
}
, die Sie dann in Zusammenhang wie folgt verwenden:
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")
);
Da die benutzerdefinierte Klasse von derselben Basisklasse abstrahiert wird, die von den integrierten Hilfsmethoden verwendet wird, kann sie wie gezeigt neben ihnen verwendet werden.
Wie der grundlegende Prozess mit dem Datum Mathe funktioniert hier ist, dass wenn Sie $subtract
ein BSON Date-Objekt aus einem anderen dann das Ergebnis ist die Millisekunden der Differenz, und in diesem Fall aus dem Epochendatum (Datum (0)) Extrahiert den Millisekundenwert. Dies ermöglicht Ihnen, die Berechnung auf den aktuellen Datumswert um den Modulo ($mod
) von der Anzahl der Millisekunden an einem Tag zu runden.
Viel wie Sie ursprünglich versucht haben, wenn Sie dann $add
dieser Millisekunde Wert zu einem BSON Date-Objekt der zurückgegebene Wert ist wieder ein BSON-Datum. Wenn Sie also ein Objekt, das epoch darstellt, hinzufügen, wird ein neues Date-Objekt zurückgegeben, das auf das aktuelle Datum gerundet wird.
Dies ist normalerweise viel nützlicher als das Extrahieren von Teilen über date aggregation operators und funktioniert auch etwas kürzer, besonders wenn man die Zeit von UTC anpasst, wie hier.
Obwohl der Bau des $group
hier ist etwas kurz und bündig als die Helferfunktionen der Feder Mongo versuchen zu vermeiden, ist es viel effizienter am Ende als eine separate $project
Stufe laufen die Feldwerte zu transformieren, dass Sie wirklich nur in der $group
Bühne sowieso wollen.
Vielen Dank für die Antwort, und vielen Dank für die Zeit zu erklären, die Mongo-Einschränkung und Workaround! Ich werde diesen Ansatz versuchen – Thiesen
Diese Antwort rockt! – nurgasemetey