Spring MongoTemplate - Mapping aggregation result to collections (e.g. List and Map)
Asked Answered
T

2

8

aggregate method of MongoTemplate returns AggregationResults<T>, where T being the class that corresponds to mongo collection.

Sometimes, we only want the single (say property abc) or a couple of properties (pqr and xyz) from that collection depending on particular criteria. In these cases, we can either retrieve the whole collection into T class or create a new class that contains properties (abc) or (pqr, xyz).

Is there a way to map these single property to List<String> or two properties as a key-value pair in HashMap<String, String>?

Trimeter answered 6/7, 2017 at 13:2 Comment(1)
I had a similar problem and solved it using another class having the elements I wanted instead of a map. How to aggregate in spring data mongo db a nested object and avoid a PropertyReferenceException?Apery
M
10

Use BasicDBObject (backed by LinkedHashMap) / Document (from 2.0.0 spring mongo version) along with java 8 stream methods to parse them into collection types.

Single Property (abc) - List type

Aggregation aggregation = Aggregation.newAggregation(Aggregation.project("abc"));
List<String> singleResults = mongoOperations.aggregate(aggregation, "collectioname", BasicDBObject.class).getMappedResults().stream().map(item -> item.getString("abc")).collect(Collectors.toList());

Multiple properties (pqr, xyz) - Map type

Aggregation aggregation = Aggregation.newAggregation(Aggregation.project("pqr, xyz"));
List<Map> multipleResults = mongoOperations.aggregate(aggregation,"collectioname", BasicDBObject.class).getMappedResults().stream().map (item -> (LinkedHashMap) item).collect(Collectors.toList());

Update ( Reading from server )

Single Property (abc) - List type

Aggregation aggregation = Aggregation.newAggregation(Aggregation.group().push("abc").as("abc"));
List<String> singleResults = (List<String>) mongoOperations.aggregate(aggregation, "collectioname", BasicDBObject.class).getUniqueMappedResult().get("abc");

Multiple properties (pqr, xyz) - Map type

Aggregation aggregation = Aggregation.newAggregation(Aggregation.group().push("pqr").as("pqr").push("xyz").as("xyz"));
Map multipleResults = mongoOperations.aggregate(aggregation,"collectioname", BasicDBObject.class).getUniqueMappedResult();
Micmac answered 6/7, 2017 at 13:35 Comment(2)
What you suggest is the more styled way of iterating aggregation results (let me know if this way is more efficient than iterating using conventional for-each loop). I was looking for a solution where the actual processing happens in MongoDB server.Trimeter
Okay I've updated answer based on your comment. Please feel free to critique.Micmac
A
1

Using Spring-data-mongodb 2.0.10 and mongo-java-driver 3.6.4 I changed the answer above to use Document instead of BasicDBObject onto a version that worked for me :

Aggregation aggregation = newAggregation(
                         //some aggregation code
                         );


    List<Document> result = mongoTemplate.aggregate(aggregation, "my_collection", Document.class).getMappedResults();
    List<String> resultList= result.stream().map(item -> item.get("_id").toString()).collect(Collectors.toList());
Accurate answered 3/9, 2019 at 9:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.