Roberto Conte Rosito


Spring Boot and MongoDB Aggregation Issues - What a pain!

Welcome back to my dev notes!

I guys, too much time is passed since my last post, but I’m back with a new one. Today I want to talk about a problem I faced with Spring Boot and MongoDB aggregations.

This problem is really annoying, and I spent a lot of time trying to solve it. The problem is that sometimes the aggregation doesn’t work as expected, and you don’t know why. The real problem is that I’ve created a suite of tests that cover all the possible cases, but sometimes the aggregation still doesn’t work as expected.

I was in trouble but after hours of debugging I remembered that I faced the same problem in the past and it took me a lot of time to solve it too (which is way I’ve turned on my blog to write about it). But let’s stop talking, and get to the point!

Suppose you have something like that in your spring boot application:


var aggregation = newAggregation(
  match(Criteria.where("field").is("value")),
  group("field").count().as("count"),
  project("count").and("field").previousOperation()
);
var result = mongoTemplate.aggregate(aggregation, "collection", YourClass.class).getMappedResults();

Sometimes, and I still don’t know why, this aggregation doesn’t work as expected. The problem is that the result list is empty. You can try to change the aggregation in many ways, and I can guarantee that I’ve tried every kind of operation, but the problem is still there, waiting for you to solve it.

You can try to get the result of aggregation in debug mode, copy it in to your MongoDB Compass instance, try to execute it and guess what? It works! But in your application no, it doesn’t work.

The solution is quite simple, but it took me a lot of time to find it. The problem is that the mongoTemplate is not able to work with the name of the collection as a string (I suppose it’s a bug but I have to investigate, for now it’s my reponsability to share what I know with you).

This line of code is wrong (or to be more precise, sometimes is wrong):

var result = mongoTemplate.aggregate(aggregation, "collection", YourClass.class).getMappedResults();

If you want to be sure that everything is executed as mongodb do, you have to pass your class instance instead of the collection name, is my habit to do thinks like that:

var collectionName = mongoTemaplte.getCollectionName(YourClass.class);

Wrong!

Do it like that:

var result = mongoTemplate.aggregate(aggregation, YourClass.class, YourClass.class).getMappedResults();

This signature is similar to the previous one, but the difference is that you pass the class instance instead of the collection name. This way the mongoTemplate is able to work with the aggregation as expected.

Believe me, I had nightmares with this problem, but now I’m happy to share the solution with you. If you know more about this problem, please let me know, I’m really interested in understanding why this happens.

For now, as always, happy coding!

comments powered by Disqus