Search code examples
javahibernatehibernate-mappinghibernate-ogmhibernate-native-query

Hibernate OGM mapping @Embeddable objects of native query


How can I read list of @Embeddable objects from MongoDB with Hibernate OGM after aggregation.

I have entity like this

@javax.persistence.Entity
public class MySession implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Type(type = "objectid") 
    private String id;
    private Date start;
    private Date end;
    @ElementCollection
    private List<MySessionEvent> events;
}

and @Embeddable object

@javax.persistence.Embeddable
public class MySessionEvent implements Serializable {
    private Long time;
    private String name;
}

I stuck with mapping Embeddable objects from native query

String queryString = "db.MySession.aggregate([" +
            "   { '$match': { 'events.name': { '$regex': 'Abrakadabra'} }}, " +
            "   { '$unwind': '$events' }, " +
            "   { '$replaceRoot': { 'newRoot': '$events'}} " +
            "])";

List<MySessionEvent> objects = em.createNativeQuery(queryString, MySessionEvent.class).getResultList();

I get an error Caused by: org.hibernate.MappingException: Unknown entity


Solution

  • Copying your comment here because it adds some details:

    I have data like this [ {id:'s1', events: [{name: 'one'},{name: 'two'}]}, {id:'s2', events: [{name: 'three'},{name: 'four'}]} ] and I want result like this [{name: 'one'},{name: 'two'},{name: 'three'},{name: 'four'}]

    The query you are running returns the following type of results if I run it on MongoDB natively (I populated it with some random data):

    { "name" : "Event 3", "time" : NumberLong(3) }
    { "name" : "Abrakadabra", "time" : NumberLong(5) }
    

    This is not enough to rebuild an entity and that's the reason you are seeing the exception.

    Considering that you only want the list of events, this should work:

    List<Object[]> poems = em.createNativeQuery( queryString ).getResultList();
    

    Hibernate OGM will convert the previous result in a list of arrays. Each element of the List is an array where the firs value of the array is the name of the event and the second one is the time.

    For supported cases like this I think HQL queries are better. You could rewrite the same example with the following:

        String queryString = 
                "SELECT e.name " +
                "FROM MySession s JOIN s.events e " +
                "WHERE e.name LIKE 'Abrakadabra'";
        List<Object[]> events = em.createQuery( queryString ).getResultList();
    

    Note that I decided not to return the time because in your comment you didn't request it, but this will work as well:

        String queryString = 
                "SELECT e.time, e.name " +
                "FROM MySession s JOIN s.events e " +
                "WHERE e.name LIKE 'Abrakadabra'";
        List<Object[]> events = em.createQuery( queryString ).getResultList();