Search code examples
javamongodbmongodb-queryaggregation-frameworkspring-mongo

Returning object in $last aggregation in spring-data-mongodb


I would like to implement the following query using spring-data-mongodb:

db.getCollection('collection').aggregate([
{ $group: {_id: "$profile", last: { $last: { firstname:"$firstname", lastname:"$lastname"}}}}])

that results in such results:

{
  "_id": "",
  "last": {
            "firstname": "",
            "lastname": ""
          }
}

However, it seems that the only API available is

GroupOperation groupOperation = Aggregation.group("profile").last("firstname").as("firstname").last("lastname").as("lastname");

this translates to:

db.getCollection('collection').aggregate([
{ $group: {_id: "$profile", firstname: { $last: "$firstname"}, lastname: { $last: "$lastname"}}}])

giving:

{
  "_id": "",
  "firstname": "",
  "lastname": ""
}

There is GroupOperation.last(AggregationExpression expr) but I do not know how to use it.

On the other hand, is there any performance penalty when using $last multiple times in one aggregate?


Solution

  • Yes this is not allowed by the constructs of the current spring mongo aggregation helpers. But you can construct your own "custom" aggregation operation Object, and then use it in the pipeline:

    public class CustomAggregationOperation implements AggregationOperation {
        private DBObject operation;
    
        public CustomAggregationOperation (DBObject operation) {
            this.operation = operation;
        }
    
        @Override
        public DBObject toDBObject(AggregationOperationContext context) {
            return context.getMappedObject(operation);
        }
    }
    

    And the usage here would be:

        Aggregation agg = newAggregation(
          new CustomAggregationOperation(
            new BasicDBObject("$group",
                new BasicDBObject("last",
                    new BasicDBObject("$last",
                        new BasicDBObject("fisrname","$firstname")
                            .append("lastname","$lastname")
                    )
                )
            )
          )
        );
    

    So you can just use BSON object constructors in order to shape that pipeline stage the way that you want. This hapilly mixes with group() and project() and all the other helper operators since it implements the AggregationOperation interface.