Reputation: 905
Assume the domain object (MyDomain) has many fileds (f1, f2, f3 ... f100), define a MyDomainRepository from MongoRepository, I want to take field name and value as parameters instead of hard code the field name as part of query method, like below:
List<MyDomain> findByNameAndValue(string name, string value);
if the name and value is "f1" and "foo", the method will find all documents whose field "f1" equals "foo".
I have googled hours and no luck.
Any help from anybody, thanks!
Upvotes: 1
Views: 7690
Reputation: 3169
pvpkiran is right, there is no such thing out of the box. You need to build your own using an injected MongoTemplate, for instance:
List<MyDomain> findByNameAndValue(string name, string value) {
Document document = new Document(name, value);
Query query = new BasicQuery(document.toJson());
return mongoTemplate.find(query, MyDomain.class);
}
The interesting thing is that you can go a little further and pass several name/value using a Map:
List<MyDomain> findByNamesAndValues(Map<String, String> parameters) {
Document document = new Document(parameters);
Query query = new BasicQuery(document.toJson());
return mongoTemplate.find(query, MyDomain.class);
}
Just in case, that works with a QueryDSL predicate too:
List<MyDomain> findByNamesAndValues(Predicate predicate) {
AbstractMongodbQuery mongoQuery = new SpringDataMongodbQuery(mongoTemplate, MyDomain.class)
.where(predicate)
Query query = new BasicQuery(mongoQuery.toString());
return mongoTemplate.find(query, MyDomain.class);
}
These methods can be further improved to handle pagination, and other cools feature such as field inclusion/exclusion.
Upvotes: 1
Reputation: 3169
You need to use QueryDSL predicates.
First, add the following dependencies to your pom.xml (assuming you're using maven to build your project):
<dependencies>
...
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-mongodb</artifactId>
</dependency>
...
</dependencies>
Also add this to your build plugins:
<build>
<plugins>
...
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.1.3</version>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/java</outputDirectory>
<processor>org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor</processor>
</configuration>
</execution>
</executions>
</plugin>
...
</plugins>
Your repository must extend QueryDslPredicateExecutor:
public interface MyDomainRepository extends MongoRepository<MyDomain, String>,
QueryDslPredicateExecutor<MyDomain> { }
Your repository will then inherit
public Iterable<MyDomain> findAll(Predicate predicate)
and a few other methods.
When you build your project, QueryDSL will generate Q-classes for you, that you can use to programmatically build predicates and query documents matching your predicates:
QMyDomain q = QMyDomain.mydomain;
Predicate p = q.f1.eq(value);
Iterable<MydDomain> i = repository.findAll(p);
To query your resources using a REST controller, you'll need something similar to:
@RestController
@RequestMapping(/"mydomain")
public class MyDomainController {
@Autowired private MyDomainRepository repository;
@GetMapping("/search/query")
public List<MyDomain> query(@QuerydslPredicate(root = MyDomain.class) Predicate predicate) {
return repository.findAll(predicate);
}
}
This last piece of code is quick and dirty made, it won't probably work as is (at least return some kind of List), but you get the idea.
Upvotes: 2