5

Per essere diretta, come faccio a fare questo:aggregazione Progetto Gruppo Di estratto giorno, mese e anno con dati Primavera

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

con molla dati

ho provato questo già e alcune altre forme ed erano non riuscite

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") 
     ); 

ho bisogno di gruppo per giorno, mese e anno in MongoDB, oppure ho bisogno di convertire tutti questi dati raggruppati in codice.

Grazie in anticipo

risposta

5

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.

+0

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

+0

Questa risposta fa scoppiare! – nurgasemetey

Problemi correlati