Question

I am looking to aggregate the following data

{
   "user": "user1",
   "error": true 
}
{
   "user": "user2",
   "error": false
}
{
   "user": "user1",
   "error": false
}

Into

{
     "_id": "user1",
     "errorCount": 1,
     "totalCount": 2
},
{
     "_id": "user2",
     "errorCount": 0,
     "totalCount": 1
}

With $cond operator, this can be achieved using:

$group: {
    _id: "$user",
    errorCount : { "$sum" : {"$cond" : ["$error", 1, 0]}},
    totalCount : { "$sum" : 1 }
}

However, since I am using Spring-data-mongodb which does not yet support $cond (as of 1.3.4-RELEASE), I couldn't do this.

Is there a way to do the same aggregation without $cond?

Was it helpful?

Solution

You are not bound to this even if there is no "functional interface" in Spring data yet. (BTW, raise a JIRA)

Just get the native form and use BasicDBObject types in the pipeline. So in principle:

    DBCollection myCollection = mongoOperation.getCollection("collection");

    <result cast> = myCollection.aggregate(<pipeline here>);

Spring data gives you abstractions, but it does not prohibit the use of the native driver functions. It actually gives you accessors to use them, as I demonstrated above.

OTHER TIPS

Thanks to Neil Lunn's suggestion, I have managed to get $cond to using aggregation support from spring-data. To do this, you have to implement the AggregationOperation interface to take in a DBObject.

public class DBObjectAggregationOperation implements AggregationOperation {
  private DBObject operation;

  public DBObjectAggregationOperation (DBObject operation) {
    this.operation = operation;
  }

  @Override
  public DBObject toDBObject(AggregationOperationContext context) {
    return context.getMappedObject(operation);
  }
}

Then you will be able to use it in TypeAggregation normally:

DBObject operation = (DBObject)JSON.parse ("your pipleline here...");
TypedAggregation<UserStats> aggregation = newAggregation(User.class,
    new DBObjectAggregationOperation(operation)
    );
AggregationResults<UserStats> result = mongoTemplate.aggregate(aggregation, UserStats.class); 

This approach will allow you to use any aggregation operator not yet defined in the framework. However, it also bypassed the validation put in place by spring-data and should be used with caution.
Please vote if you would like to have $cond operator supported properly through the framework: https://jira.springsource.org/browse/DATAMONGO-861

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top