8

Using spring-data-mongodb-1.5.4 and mongodb-driver-3.4.2

I've a class Hotel

    public class Hotel {

        private String name;
        private int pricePerNight;
        private Address address;
        private List<Review> reviews;
//getter, setter, default constructor, parameterized constructor 

Review class :

public class Review {

    private int rating;
    private String description;
    private User user;
    private boolean isApproved;
 //getter, setter, default constructor, parameterized constructor 

When I am calling Aggregation.unwind("reviews"); it throws

org.springframework.data.mapping.model.MappingInstantiationException: Failed to instantiate java.util.List using constructor NO_CONSTRUCTOR with arguments

UnwindOperation unwindOperation = Aggregation.unwind("reviews");
Aggregation aggregation = Aggregation.newAggregation(unwindOperation);
AggregationResults<Hotel> results=mongoOperations.aggregate(aggregation,"hotel", Hotel.class);

I see this question but does't help me.

How to resolve this?

1
  • 2
    9/10 times you really just want a plain BSON object like Document.class or DBObject.class for the aggregation output. Aggregations change the output shape by definition of what they are meant to do. Typically you just don't need a strict type for output, unless you really need some custom serialization. For everything else, just use the generics. That's what they are there for. Commented Sep 10, 2017 at 11:10

3 Answers 3

13

When you $unwind reviews field, query's return json structure does not match with your Hotelclass anymore. Because $unwindoperation makes reviews a sub object instead of a list. If you try your query in robomongo or some other tools, you can see your return object is like that

{
  "_id" : ObjectId("59b519d72f9e340bcc830cb3"),
  "id" : "59b23c39c70ff63135f76b14",
  "name" : "Signature",
  "reviews" : {
    "id" : 1,
    "userName" : "Salman",
    "rating" : 8,
    "approved" : true
  }
}

So you should use another class instead of Hotellike UnwindedHotel

public class UnwindedHotel {

    private String name;
    private int pricePerNight;
    private Address address;
    private Review reviews;
}

UnwindOperation unwindOperation = Aggregation.unwind("reviews");
Aggregation aggregation = Aggregation.newAggregation(unwindOperation);
AggregationResults<UnwindedHotel> results=mongoOperations.aggregate(aggregation,"hotel", UnwindedHotel.class);
Sign up to request clarification or add additional context in comments.

3 Comments

You saved me again :)
@MehrajMalik Happy to help. And a general suggestion which I do for my queries. First build them as native mongodb query and try it directly via robomongo etc. Then code it into spring-data. So you can be sure your query works and return values as expected.
Thanks for the golden tip.
0

It occurs to me a very different problem making me crazy for long time a day ago and I think it could be very useful to share here even if it is not about unwind:

  • at the beginning I design a model with java + mongoDB in which I put some fields in a key inside a document and made several tests, for example {"header":{"key":"first", "value": 4}}
  • then I changed my mind and think not to have simple nested objects but a list of them to be more general such as {"header":[{"key":"first", "value": 4}] }

When I was working only with new documents all was running fine, but then making more general tests I continuously had crashes with this mongodb error about List because in my DB I had old documents without list but with simple objects I forgot to remove and which were in conflict with the new model wanting a list.

Simple had I to clean DB and starting tests from scratch.

Comments

0

U dont have to clean the Db ,just rename the previous collection and create a new collection with the name mentioned in the properties/yml file on your project and save it in the mongoDb database.

then run your project and save the new data using the save Api and u can observe the changes from comparing both the collections.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.