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>?

s7vr
  • 73,656
  • 11
  • 106
  • 127
Harish
  • 169
  • 1
  • 2
  • 7
  • 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?](https://stackoverflow.com/q/57910383/7747942) – Sylhare Sep 12 '19 at 20:22

2 Answers2

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();
s7vr
  • 73,656
  • 11
  • 106
  • 127
  • 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. – Harish Jul 10 '17 at 15:50
  • Okay I've updated answer based on your comment. Please feel free to critique. – s7vr Jul 10 '17 at 16:11
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());
Buzzo
  • 143
  • 1
  • 8