Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

164
Vistas
MongoDB group by query running from Spring MongoTemplate does not return sum

I have the following query which works fine when running from MongoDB shell:

db.feedback.aggregate([
    {
        $group: {
           _id: {
               year: { $year: '$receivedDate' }, 
               month: { $month: '$receivedDate' }
           }, 
           count: { $sum: 1 }
        }
    }
])

It returns dates (year, month) and their sum.

However, when I run the same query from Spring's MongoTemplate I get the date, and the sum is always null:

private static final String QUERY_STATS_BY_MONTH = "{
    aggregate: 'feedback', 
    pipeline: ([
        {
            $group:{
                _id: {
                    year: { $year: '$receivedDate' }, 
                    month: { $month: '$receivedDate' }
                }, 
                count: { $sum: 1 }
            }
        } 
    ])";
    ....


    CommandResult commandResult = mongoTemplate.executeCommand(QUERY_STATS_BY_DAY);
    BasicDBList dbList = (BasicDBList) commandResult.get(QUERY_RESULT);
    Iterator<Object> it = dbList.iterator();
    List<FeedbackDateAggregation> res = new ArrayList();
    while (it.hasNext()) {
        DBObject dbObject = (DBObject) it.next();
        res.add(mongoTemplate.getConverter().read(FeedbackDateAggregation.class, dbObject));
    }
    return res;

My domain classes are:

public class FeedbackDateAggregation {

    private StatsDate id;
    private Long count;

    public Long getCount() {
        return count;
    }

    public void setCount(Long count) {
        this.count = count;
    }

    public StatsDate getId() {
        return id;
    }

    public void setId(StatsDate id) {
        this.id = id;
    }
}

and:

public class StatsDate {

    private int year;
    private int month;
    private int day;
    private int week;

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public int getMonth() {
        return month;
    }

    public void setMonth(int month) {
        this.month = month;
    }

    public int getDay() {
        return day;
    }

    public void setDay(int day) {
        this.day = day;
    }

    public int getWeek() {
        return week;
    }

    public void setWeek(int week) {
        this.week = week;
    }
}

The StatsDate are retrieved, but count is always null.

over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

This is the idiomatic way of doing aggregation queries using spring template. You don't need to access the low level CommandResult mongo api, only need for advance use.

Makes use of AggregationOperation as the operator $year and $month are not supported out of box in the spring group stage yet.

AggregationOperation group = new AggregationOperation() {
  @Override
  public DBObject toDBObject(AggregationOperationContext context) {
    return new BasicDBObject(
            "$group", new BasicDBObject(
              "_id", new BasicDBObject(
                "year", new BasicDBObject("$year", "$receivedDate")).append(
                "month", new BasicDBObject("$month", "$receivedDate"))).append(
            "count", new BasicDBObject("$sum", 1)));
   }
};

newAggregation is the static helper method which takes a list of pipeline stages.

Aggregation aggregation = newAggregation(group);

Finally, mongo template aggregate method to run the query.

List<FeedbackDateAggregation> res = mongoTemplate.aggregate(aggregation, "feedback", FeedbackDateAggregation.class).getMappedResults();

Generated Query:

{
    "aggregate": "__collection__",
    "pipeline": [{
        "$group": {
            "_id": {
                "year": {
                    "$year": "$receivedDate"
                },
                "month": {
                    "$month": "$receivedDate"
                }
            },
            "count": {
                "$sum": 1
            }
        }
    }]
}
over 4 years ago · Santiago Trujillo Denunciar

0

You could try projecting the fields you want to use as the group by keys first by using the SpEL andExpression in the projection operation and then group by the new fields in the group operation:

Aggregation agg = newAggregation(
    project("id")
        .andExpression("month(receivedDate)").as("month")
        .andExpression("year(receivedDate)").as("year"),
    group("year", "month").count().as("count")
);

AggregationResults<FeedbackDateAggregation> results = mongoTemplate.aggregate(
    agg, 
    "feedback", 
    FeedbackDateAggregation.class
);
List<FeedbackDateAggregation> res = results.getMappedResults();

In the above a new aggregation via the newAggregation static factory method is created to which you pass a list of aggregation operations. These aggregate operations define the aggregation pipeline of your Aggregation.

In the first step you project the fields from the input collection by using the SpEL andExpression with the project operation.

In the second step you use the group operation to define a group for each "year" and "month"-value for which you aggregate the occurrence count via the count() aggregation operator and collect the result in a new field called "count".

Finally call the aggregate() Method on the MongoTemplate in order to let MongoDB perform the actual aggregation operation with the created Aggregation as an argument.

over 4 years ago · Santiago Trujillo Denunciar

0

The problem was that I used an old version of Fongo (fake mongo for tests). Once I tried it on a real MongoDB, it worked like a charm. When I updated my Fongo version, it worked as well. I also had to change my domain objects. I have now a domain object that includes day, week, month, year, count.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda