Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MongoRepository dynamic queries

I have the following problem. Lets say I have the following model object:

class Person {
    String id;
    String firstName;
    String lastName;
    Map<String, String> properties;
}

In the properties map, you can insert any kind of property, there are no constrains.

The above object is saved in a MongoDB which looks like this:

public interface PersonRepo extends MongoRepository<Person, String> {
}

When a person is saved into the repository the Map<String, String> properties is flatten up. As an example, if we have the following object:

Person: {
    id := 1;
    firstName := John,
    lastName  := Doe,
    properties := {
        age: 42
    }
}

the document saved in the MongoRepository will be the following:

Person: {
    id := 1;
    firstName := John,
    lastName  := Doe,
    age := 42
}

Now my problem is that I have to look for objects based on (for example), if they have a specific property or not. Lets say I want all Persons for which an age property has been defined. One important additional requirement is that I should return a paged result.

I've tried using the

findAll(Example<Person> example, Pageable pageable)

But this does not work for some reason. I suspect that it's the fact that my model object and the MongoDB Document have different structures.

I've also tried with the QueryDsl (here you have an example: http://www.baeldung.com/queries-in-spring-data-mongodb) but with no success either, and also to me this solution is not to elegant (having to mantain generated classes and alike. Also I have a feeling it will not work because of my Map<String, String> properties object member).

Another solution that came to my mind and would be elegant enough, is to have the following function:

@Query(value = "?0")
Page<Query> findByQuery(String query, Pageable pageable)

In this case I would be able to manually construct the query and I wouldn't have to hardcode the key by which I run the search. My question now is, how can set the query value to be exactly my first parameter? With the example showned above I get the following error

java.lang.ClassCastException: java.lang.String cannot be cast to com.mongodb.DBObject

One other solution would be to use mongoTemplate and query given some Criteria as in the following example:

    final Query query = new Query();
    query.addCriteria(Criteria.where("age").regex(".*"));

    mongoTemplate. find(query, Person.class);

The problem with this solution is that it returns a list of objects instead for a paged result. It cal also return a specific page if I add query.with(new PageRequest(3, 2)); but in this case I cannot manually construct the "paged" result because I do not know the total number of elements.

Do you have any other ideas that could help me?

Thanks in advance!

like image 557
Cristian Balint Avatar asked Oct 19 '25 04:10

Cristian Balint


1 Answers

There is a realy easiest way to do this, similar to your code:

@Query(value = "?0")
Page<Query> findByQuery(String query, Pageable pageable)

But passing your query as a BSONObject instead of String

@Query("?0")
Page<Query> findByQuery(BSONObject query, Pageable pageable)
like image 61
Jhoni Carlos Avatar answered Oct 21 '25 21:10

Jhoni Carlos



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!