Using $cond operator with Spring-data-mongodb [duplicate]
-
21-12-2019 - |
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?
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