Home > OS >  Spring Mongo Aggregation give a conversion error
Spring Mongo Aggregation give a conversion error

Time:11-22

I'm trying to use Mongo aggregation but I receive an error that I don't understand.

This is my domain:

   @Document(collection = "tapes")
   public class Tape {

      @Id
      private String id;

      private String area;

      private Integer tape;

      private String tapeModel;
    
     // follow getters e setters

The mongo shell command and the output is the following:

> db.tapes.aggregate([{ $group: { _id: { "area":"$area"}, tapes: {$push: {tape: "$tape"}}}}  ])
{ "_id" : { "area" : "free" }, "tapes" : [ { "tape" : 1 }, { "tape" : 2 } ] }
{ "_id" : { "area" : "Qnap" }, "tapes" : [ { "tape" : 3 } ] }

The following is an attempt to re-create the aggregation in Spring:

AggregationOperation group = Aggregation.group("area").push("tape").as("tape");
Aggregation aggregation = Aggregation.newAggregation(group);
AggregationResults<Tape> results = mongoTemplate.aggregate(aggregation, "tapes", Tape.class);
//List<Tape> tapes = mongoTemplate.aggregate(aggregation, mongoTemplate.getCollectionName(Tape.class), Tape.class).getMappedResults();
List<Tape> tapes = results.getMappedResults();
System.out.println(tapes);

But I obtain the following error:

Cannot convert [3] of type class java.util.ArrayList into an instance of class java.lang.Integer! Implement a custom Converter<class java.util.ArrayList, class java.lang.Integer> and register it with the CustomConversions. Parent object was: it.unifi.cerm.cermadminspring.domain.Tape@2b84da07 -> null
org.springframework.data.mapping.MappingException: Cannot convert [3] of type class java.util.ArrayList into an instance of class java.lang.Integer! Implement a custom Converter<class java.util.ArrayList, class java.lang.Integer> and register it with the CustomConversions. Parent object was: it.unifi.cerm.cermadminspring.domain.Tape@2b84da07 -> null

I don't understand why, I searched for aggregation examples and all are more or less similar to mine.

Someone can help me?

CodePudding user response:

First, for making life easier, a more simplified aggregation can be used:

> db.tapes.aggregate([ {$group: {_id: "$area", tapes: {$push: "$tape"}}} ])

Which should yield:

{ "_id" : "free", "tapes" : [  1 , 2  ] }
{ "_id" : "Qnap", "tapes" : [  3  ] }

Which should be matched by a change to the Java group aggregation operation: AggregationOperation group = Aggregation.group("area").push("tape").as("tapes");
Note that I've changed to plural: as("tapes")

Then, notice that you are actually returning a document which doesn't have the same structure as the one you've mapped in the Tape class. That document contains two fields, the String id and a List<Integer> tapes fields.

This is the reason for the shorthand group aggregation I've suggested above, for making mapping easier:

public class TapesForArea {

    private String id; // which is the area

    private List<Integer> tapes;

    // getters, setters ...
}

You don't need to map this class using spring-data-mongodb annotations.

Finally, have the aggregation results return the right type:

AggregationResults<TapesForArea> results = 
    mongoTemplate.aggregate(aggregation, "tapes", TapesForArea.class);
List<TapesForArea> tapes = results.getMappedResults();

BTW, the error comes from the fact that you try to map the single item tape array [ 3 ] into private Integer tape; property of Tape class.

  • Related