I have MongoDB Page and Post collections. Each page document has field postIds which is array of post Ids (String objects). I want to use aggregation to count number of posts (=number of elements in array postIds) for each page. I wrote Mongo Shell aggregation function which returns exactly what I want:
db.page.aggregate([
{$unwind : '$postIds'},
{$group : {_id: '$_id', 'sum': { $sum: 1}}}
])
and it returns this result:
{ "_id" : "3", "sum" : 3 }
{ "_id" : "2", "sum" : 3 }
This means that page with id 3 has 3 posts, and page with id 2 has 3 posts as well, which is correct.
Now I wanted to write same using Spring MongoDB Aggregation, and wrote this simple JUnit test:
/**
* Test page posts count
*/
@Test
public void testPagePostsCount() throws Exception{
MongoTemplate template = repository.getMongoTemplate();
Page page = new Page();
page.setPageId("2210");
page.setUserId("azec");
List<String> postList = new ArrayList<String>();
postList.add("53eb1a560efbe048c7ea698d");
postList.add("53eb1a6b0efbe048c7ea698e");
page.setPostIds(postList);
template.save(page);
Aggregation agg = newAggregation(
match(Criteria.where("pageId").is("2210")),
unwind("postIds"),
group("_id").sum("1").as("sum")
//project("$sum").and("pageId").previousOperation()
);
AggregationResults<PostCount> results = template.aggregate(agg, "page", PostCount.class);
List<PostCount> postCount = results.getMappedResults();
System.out.println("Done!");
}
However, this aggregation query returns this native Mongo query:
2014-08-13 20:06:07,949 DEBUG [org.springframework.data.mongodb.core.MongoTemplate] - Executing aggregation:
{
"aggregate":"page",
"pipeline":[
{
"$match":{
"pageId":"2210"
}
},
{
"$unwind":"$postIds"
},
{
"$group":{
"_id":"$_id",
"sum":{
"$sum":"$1"
}
}
}
]
}
Questions: 1. As you can see, the difference is with the $sum value of $1. I need to pass there number 1 instead of $1, but I am not sure how. 2. Do I need project operation here?
Thanks
I have figured this out finally. The key is to use count() aggregation function in Spring Data for MongoDB, which translates to sum increments by 1 in native Mongo shell. This is my final JUnit Test:
/**
* Test page posts count
*/
@Test
public void testPagePostsCount() throws Exception{
MongoTemplate template = repository.getMongoTemplate();
Page page = new Page();
page.setPageId("2210");
page.setUserId("azec");
List<String> postList = new ArrayList<String>();
postList.add("53eb1a560efbe048c7ea698d");
postList.add("53eb1a6b0efbe048c7ea698e");
page.setPostIds(postList);
template.save(page);
Aggregation agg = newAggregation(
match(Criteria.where("_id").is("2210")),
unwind("postIds"),
group("_id").count().as("nPosts"),
project("nPosts").and("_id").as("pageId")
);
AggregationResults<PostCount> results = template.aggregate(agg, "page", PostCount.class);
List<PostCount> postCount = results.getMappedResults();
Assert.assertTrue(!postCount.isEmpty());
Assert.assertTrue(postCount.get(0).nPosts == 2);
Assert.assertTrue(postCount.get(0).pageId.equals("2210"));
}
private class PostCount {
String pageId;
int nPosts;
}
So finally this translates to following native aggregation operation:
{
"aggregate":"page",
"pipeline":[
{
"$match":{
"_id":"2210"
}
},
{
"$unwind":"$postIds"
},
{
"$group":{
"_id":"$_id",
"nPosts":{
"$sum":1
}
}
},
{
"$project":{
"nPosts":1,
"pageId":"$_id"
}
}
]
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With