Search code examples
mongodbspring-data-mongodb

TopN aggregations on spring-data-mongodb


I am trying to implement a grouping with a TopN aggregation operator using spring-data-mongo and I am lost on how to do it.

I know what I want from the POV of MongoDB. It's something like this:

[ { 
    $match: { 
      field000: { $regex: ".*MATCHTHIS.*" }, 
      created: { $lte: new Date("2030-05-25T00:00:00.000+00:00" ) } 
    }, 
  }, 
  { 
     $group: { 
       _id: "$field001", 
       field001s: { 
         $topN: { 
           output: ["$field002", "$created"], 
           sortBy: { created: -1, }, 
           n: 1, 
         }
       }
     }
    }]

Meaning ... for the set of documents already filtered by the $match clause; group by field001, order each bucket by created desc, and pick the top (1). So the most recently created documents for each group category.

I find problems to translate this into spring-data-mongo


Solution

  • After a lot of research, I realized this question is probably easily solvable on spring-data-mongodb most recent versions since "topN" aggregation operator is implemented. However in my case upgrading the stack to support that version is not an option.

    On the other hand, if you are using repositories then the @Charchit Kapoor solution is probably the best one.

    If you want to stick with mongo template it can be done this way:

        AggregateIterable<Document> result = mongoOps.getCollection(COLLECTION_NAME).aggregate(Arrays.asList(new Document("$match",
            new Document("field000",
              new Document("$regex", ".*REGEXP_FIELD_000.*"))
              .append("created",
                new Document("$lte",
                  new java.util.Date(1685318400000L)))),
          new Document("$group",
            new Document("_id", "$field001")
              .append("Field0001s",
                new Document("$topN",
                  new Document("output", Arrays.asList("$field002", "$created"))
                    .append("sortBy",
                      new Document("created", -1L))
                    .append("n", 1L))))));
    

    You can split this into different methods for better readability.