![](/img/trans.png)
[英]How to combine AND and OR clause using @Query in Spring-Data-MongoDB?
[英]spring-data-mongodb optional query parameter
我正在使用 spring-data-mongodb。
我想通过在查询中传递一些可选参数来查询数据库。
我有一个域类。
public class Doc {
@Id
private String id;
private String type;
private String name;
private int index;
private String data;
private String description;
private String key;
private String username;
// getter & setter
}
我的控制器:
@RequestMapping(value = "/getByCategory", method = RequestMethod.GET, consumes = MediaType.APPLICATION_JSON, produces = MediaType.APPLICATION_JSON)
public Iterable<Doc> getByCategory(
@RequestParam(value = "key", required = false) String key,
@RequestParam(value = "username", required = false) String username,
@RequestParam(value = "page", required = false, defaultValue = "0") int page,
@RequestParam(value = "size", required = false, defaultValue = "0") int size,
@RequestParam(value = "categories") List<String> categories)
throws EntityNotFoundException {
Iterable<Doc> nodes = docService.getByCategory(key, username , categories, page, size);
return nodes;
}
这里Key和username是可选的查询参数。
如果我通过其中任何一个,它应该返回具有给定密钥或用户名的匹配文档。
我的服务方式是:
public Iterable<Doc> getByCategory(String key, String username, List<String> categories, int page, int size) {
return repository.findByCategories(key, username, categories, new PageRequest(page, size));
}
存储库:
@Query("{ $or : [ {'key':?0},{'username':?1},{categories:{$in: ?2}}] }")
List<Doc> findByCategories(String key, String username,List<String> categories, Pageable pageable);
但是通过使用上述查询,它不会返回具有给定键或用户名的文档。 我的查询有什么问题?
就个人而言,我当时会放弃接口驱动的存储库模式,创建一个@Autowire
sa MongoTemplate 对象的 DAO,然后使用Criteria
查询数据库。 这样,您就有了清晰的代码,不会扩展@Query
注释的功能。
所以,像这样的东西(未经测试,伪代码):
@Repository
public class DocDAOImpl implements DocDAO {
@Autowired private MongoTemplate mongoTemplate;
public Page<Doc> findByCategories(UserRequest request, Pageable pageable){
//Go through user request and make a criteria here
Criteria c = Criteria.where("foo").is(bar).and("x").is(y);
Query q = new Query(c);
Long count = mongoTemplate.count(q);
// Following can be refactored into another method, given the Query and the Pageable.
q.with(sort); //Build the sort from the pageable.
q.limit(limit); //Build this from the pageable too
List<Doc> results = mongoTemplate.find(q, Doc.class);
return makePage(results, pageable, count);
}
...
}
我知道这与运行时生成数据库代码的趋势背道而驰,但在我看来,它仍然是更具挑战性的数据库操作的最佳方法,因为它更容易看到实际发生的情况。
不直接支持根据输入值过滤掉部分查询。 不过,它可以使用@Query
的$and
运算符和一点SpEL来完成。
interface Repo extends CrudRepository<Doc,...> {
@Query("""
{ $and : [
?#{T(com.example.Repo.QueryUtil).ifPresent([0], 'key')},
?#{T(com.example.Repo.QueryUtil).ifPresent([1], 'username')},
...
]}
""")
List<Doc> findByKeyAndUsername(@Nullable String key, @Nullable String username, ...)
class QueryUtil {
public static Document ifPresent(Object value, String property) {
if(value == null) {
return new Document("$expr", true); // always true
}
return new Document(property, value); // eq match
}
}
// ...
}
无需通过T(...)
类型表达式来寻址目标函数,而是编写一个EvaluationContextExtension
(有关详细信息,请参阅: json spel ),这样可以摆脱一遍又一遍地重复类型名称。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.