Si esegue in una limitazione di mongo primavera in quello che si può fare per i calcoli di campo in un unico $project
fase, e in effetti è probabile che già scrivendo come un separato $project
poiché si scopre che si Al momento non è possibile progettare campi personalizzati con nome direttamente in $group
_id
.
Quindi sarebbe meglio tenere tutto questo nello $group
, nonché utilizzare un metodo diverso per arrotondare le date regolate all'ora locale.
Il modo migliore per scrivere il vostro $group
sarebbe quindi:
{ "$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" }
}}
Naturalmente per utilizzare questo tipo di struttura con molla-Mongo è necessario un'implementazione personalizzata dell'operazione fase di aggregazione che può prendere un definito 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);
}
}
che poi utilizzare nel contesto come questo:
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")
);
Poiché la classe personalizzata si astrae dalla stessa classe base utilizzata dai metodi di aiuto incorporati, può essere utilizzata insieme a loro come mostrato.
Come il processo di base con la matematica della data funziona qui è che quando si usa un oggetto Date BSON da un altro $subtract
da un altro il risultato è il millisecondo della differenza, e in questo caso dalla data di epoca (Data (0)) che estrae il valore in millisecondi. Ciò consente di eseguire il calcolo matematico per arrotondare al valore di data corrente dal modulo ($mod
) dal numero di millisecondi in un giorno.
Proprio come si è tentato in origine, quando si è quindi $add
con valore millisecondo in un oggetto Date BSON, il valore restituito è nuovamente una Data BSON. Quindi l'aggiunta a un oggetto che rappresenta l'epoca restituisce un nuovo oggetto data, ma arrotondato alla data corrente.
Questo è di solito molto più utile dell'estrazione di parti tramite date aggregation operators, e funziona anche per essere un po 'più breve al codice, specialmente quando si regola l'ora da UTC come si fa qui.
Sebbene la costruzione di $group
qui sia un po 'più concisa rispetto alle funzioni di supporto di spring mongo che stanno cercando di evitare, è molto più efficiente alla fine che eseguire uno stage separato $project
per trasformare i valori di campo che voglio solo nella fase $group
comunque.
Grazie mille per la risposta, e grazie per aver speso questo tempo per spiegare la limitazione e la soluzione di mongo! Proverò questo approccio – Thiesen
Questa risposta fa scoppiare! – nurgasemetey