MongoDB $aggregate $push multiple fields in Java Spring Data

后端 未结 3 1099
情歌与酒
情歌与酒 2020-11-29 10:47

I have a mongo aggregate group query:

db.wizard.aggregate(
{
$group: {
    _id: \"$title\",
    versions: { $push: {version:\"$version\", author:\"$author\",         


        
相关标签:
3条回答
  • 2020-11-29 11:08

    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"));
    
    0 讨论(0)
  • 2020-11-29 11:16

    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.

    0 讨论(0)
  • 2020-11-29 11:24

    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"),
        ...
    );
    
    0 讨论(0)
提交回复
热议问题