MongoDB $aggregate $push multiple fields in Java Spring Data MongoDB $aggregate $push multiple fields in Java Spring Data mongodb mongodb

MongoDB $aggregate $push multiple fields in Java Spring Data


You can directly pass the BasicDbObject to any of the aggregation pipeline stage.

Aggregation agg = newAggregation(            group("title").            push(new BasicDBObject                   ("version", "$version").append                   ("author", "$author").append                   ("dateAdded", "$dateAdded")).as("versions"));


Note: MongoDB versiĆ³n 2.6 - 3.0 (compatible Java driver)

I've extended org.springframework.data.mongodb.core.aggregation.AggregationOperation class to implement custom toDBObject method:

public class GenericAggregationOperation implements AggregationOperation {    private String operator;    private DBObject query;    /**     * Default constructor.     *      * @param operator MongoDB operator ($group, $sort, $project, etc..)     * @param query MongoDB aggregation query step string     */    public GenericAggregationOperation(String operator, String query) {        this(operator, (DBObject) JSON.parse(query));    }    /**     * Default constructor.     *      * @param operator MongoDB operator ($group, $sort, $project, etc..)     * @param query MongoDB aggregation query step DBObject     */    public GenericAggregationOperation(String operator, DBObject query) {        this.operator = operator;        this.query    = query;    }    @Override    public DBObject toDBObject(AggregationOperationContext context) {        return new BasicDBObject(operator, query);    }}

In your case, it would be:

List<AggregationOperation> list = new ArrayList<AggregationOperation>();lista.add(new GenericAggregationOperation("$group", "{ \"_id\": \"$title\", \"versions\": { \"$push\": { \"version\":\"$version\", \"author\":\"$author\", \"dateAdded\":\"$dateAdded\"}} }"));TypedAggregation<EpisodeIndexDto> agg = Aggregation.newAggregation(    YourClassTitleVersion.class, list);mongoOperations.aggregate(agg, YourClassTitleVersion.class,    YourClassTitleVersion.class).getMappedResults();

Hope this helps you.


In the new version spring-data-mongodb:2.x.x the AggregationOperation need to return Document instead of DBObject, so the updated class will be:

import com.mongodb.BasicDBObject;import com.mongodb.DBObject;import org.bson.Document;import org.springframework.data.mongodb.core.aggregation.AggregationOperation;import org.springframework.data.mongodb.core.aggregation.AggregationOperationContext;public class GenericAggregationOperation implements AggregationOperation {    private String operator;    private DBObject query;    public GenericAggregationOperation(String operator, DBObject query) {        this.operator = operator;        this.query = query;    }    public GenericAggregationOperation(String operator, String query) {        this(operator, BasicDBObject.parse(query));    }    @Override    public Document toDocument(AggregationOperationContext context) {        return new Document(operator, query);    }}

Plus to make it easier to be used I'll add utility interface (java 8+, for java 7 or lower you can convert this to class utils instead):

import com.mongodb.DBObject;import org.springframework.data.mongodb.core.aggregation.AggregationOperation;public interface GenericAggregationUtils {    static AggregationOperation aggregate(String operation, String query) {        return new GenericAggregationOperation(operation, query);    }    static AggregationOperation aggregate(String operation, DBObject query) {        return new GenericAggregationOperation(operation, query);    }}

And then we can static import the interface into our class:

import static com.example.mongodb.aggregation.GenericAggregationUtils.*;

And use it in the aggregation pipeline together with other spring data AggregationOperation like this:

Aggregation aggregation = newAggregation(YourDocCollection.class,    aggregate("$group", "{ \"_id\": \"$title\", \"versions\": { \"$push\": { \"version\":\"$version\", \"author\":\"$author\", \"dateAdded\":\"$dateAdded\"}} }"),    sort(Sort.Direction.ASC, "title"),    ...);