Search code examples
javamongodbmongodb-queryaggregation-frameworkspring-mongo

Use $stdDevSamp or $stdDevPop with Spring Mongo


I'd like to know how to implement a Standard Deviation aggregation Function to use in Spring Mongo Data.

I Know Mongo DB 3.2 has a Standard Deviation aggregation function, but It isn't available in Spring Data.

Could I use the Mongo's aggregation function?

Thanks.


Solution

  • There is a distinct difference between "not available" and "no implemented helper method", and that is the real case here. Just because there is no "helper" for implementing the $stdDevSamp or $stdDevPop operators, does not mean they cannot be used, as long as you are connecting to a MongoDB 3.2 instance of course.

    All you really need is a custom class supporting the AggregationOperation interface, that will allow construction using DBObject:

    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);
        }
    }
    

    Then you can use that class in aggregation pipeline construction like so:

    Aggregation aggregation = newAggregation(
        new CustomAggregationOperation(
            new BasicDBObject("$sample", new BasicDBObject("size",100))
        ),
        new CustomAggregationOperation(
            new BasicDBObject(
                "$group",
                new BasicDBObject("_id",null)
                    .append("ageStdDev",new BasicDBObject("$stdDevSamp","$age"))
            )
        )
    );
    

    And that is the equivalent of the documentation example:

    db.users.aggregate(
       [
          { "$sample": { "size": 100 } },
          { "$group": { "_id": null, "ageStdDev": { "$stdDevSamp": "$age" } } }
       ]
    )
    

    As an interface for AggregationOperation the class easily mixes with the implemented helpers:

    Aggregation aggregation = newAggregation(
        // Using the match helper for the `$match` stage
        match(
            Criteria.where("age").gte(20).lte(50)
        ),
        // Mixed in with custom classes for the others
        new CustomAggregationOperation(
            new BasicDBObject("$sample", new BasicDBObject("size",100))
        ),
        new CustomAggregationOperation(
            new BasicDBObject(
                "$group",
                new BasicDBObject("_id",null)
                    .append("ageStdDev",new BasicDBObject("$stdDevSamp","$age"))
            )
        )
    );
    

    So you can still use features even if there is no "buit in helper" to work out the BSON Object construction for you. You just do the construction yourself.