Search code examples
mongodbaggregation-frameworkspring-data-mongodbdatabase

Group by array of document in Spring Mongo Db


How can I group by tagValue in Spring and MongoDb? MongoDB Query :

db.feed.aggregate([                 
    { $group: { _id: "$feedTag.tagValue", number: { $sum : 1 } } },
    { $sort: { _id : 1 } }        
])

How can I do the same thing in Spring MongoDB, may be using Aggregation method? Sample document of feed collections:

{
    "_id" : ObjectId("556846dd1df42d5d579362fd"),   
    "feedTag" : [ 
        {
            "tagName" : "sentiment",
            "tagValue" : "neutral",
            "modelName" : "sentiment"
        }
    ],    
    "createdDate" : "2015-05-28"
}

Solution

  • To group by tagValue, since this is an array field, you need to apply the $unwind pipeline step before the group to split the array so that you can get the actual count:

    db.feed.aggregate([  
        {'$unwind': '$feedTag'},
        {'$group': { 
            '_id': '$feedTag.tagValue', 
            'number': { '$sum' : 1 } 
        }},
        {'$sort': { '_id' : 1 }}        
    ])
    

    The following is the equivalent example in Spring Data MongoDB:

    import static org.springframework.data.mongodb.core.aggregation.Aggregation.*;
    
    Aggregation agg = newAggregation(    
        unwind("feedTag"),
        group("feedTag.tagValue").count().as("number"),    
        sort(ASC, "_id") 
    );
    
    // Convert the aggregation result into a List
    AggregationResults<Feed> results = mongoTemplate.aggregate(agg, "feed", Feed.class);
    List<Feed> feedCount = results.getMappedResults();
    

    From the above, a new aggregation object is created via the newAggregation static factory method which is passed a list of aggregation operations that define the aggregation pipeline of your Aggregation.

    The firt step uses the unwind operation to generate a new document for each tag within the "feedTag" array.

    In the second step the group operation defines a group for each embedded "feedTag.tagValue"-value for which the occurrence count is aggregated via the count aggregation operator.

    As the third step, sort the resulting list of feedTag by their tagValue in ascending order via the sort operation.

    Finally call the aggregate Method on the MongoTemplate to let MongoDB perform the actual aggregation operation with the created Aggregation as an argument.

    Note that the input collection is explicitly specified as the "feed" parameter to the aggregate Method. If the name of the input collection is not specified explicitly, it is derived from the input-class passed as first parameter to the newAggreation Method.