Search code examples
javamongodbaggregation

How to aggregate "sum" and "date" with MongoDB Java driver


I am looking for an up-to-date example on how to do "sum" and "date" aggregations with the MongoDB Java Driver. I am using mongodb-driver-sync version 4.11.1.

Having the following data model:

{
  "_id": {
    "$oid": "654e3f36582773107c4570f1"
  },
  "booked": {
    "$date": "2011-01-05T01:00:00.000Z"
  },
  "amount": {
    "$numberDecimal": "45.08"
  }
}

First thing i'd like to do is sum the amount of all data entries. However, the examples I have found, only use "count" which doesn't help much. One example of this is on the official documentation.

Arrays.asList(
            Aggregates.match(Filters.eq("categories", "Bakery")),
            Aggregates.group("$stars", Accumulators.sum("count", 1))
    )

See: https://www.mongodb.com/docs/drivers/java/sync/current/fundamentals/aggregation/#aggregation-expression-example

Second thing i'd like to do is to group by month or year sometimes both. Based one the documentation, I would assume this should be done with Accumulators, but there are no date based Accumulators, only sum, avg, etc. So something like this won't work:

List<Bson> pipeline = Arrays.asList(group("_id", Accumulators.month ... ));

Solution

  • Answer my own question in hope that it will help:

    For getting the sum it was pretty simple by just using an Accumulator.

    Bson groupStage = group("_id", Accumulators.sum("totalAmount", "$amount"));
    
    AggregateIterable aggregation = collection("bookings").aggregate(of(matchStage, groupStage));
    

    The trick here is to watch out if your are aggregation on POJOa or on the collection. If you have a field (in this case totalAmount) in your POJO than this works fine, otherwise it will return null in your POJO. As for the example, I decided to aggregate on the collection.

    For group on date, it seems there are no direct classes in the Java Mongo Driver, so I decided to use the direct JSON equivalent and ended up with:

    Bson groupStage = group(Document.parse("{'year': { $year: '$booked' }}"));
    
    AggregateIterable aggregation = collection("bookings").aggregate(Arrays.asList(groupStage));