什么@Query使MongoRepository忽略空白参数?

时间:2017-10-05 06:55:46

标签: mongodb spring-data-mongodb

我有这个查询界面:

public interface IMyDocDao extends MongoRepository<MyDoc, String> {

   @Query(value = "{ 'stuff.in.nested.doc' : ?0, 'another.stuff.in.nested.doc' : ?1 }")
   List<MyDoc> findByFoo(String foo, String bar);
}

如果来电findByFoo("a", "b")可以正常使用。

如果来电findByFoo("", "b"),则会返回第一个参数为空白且第二个参数为&#34; b&#34;的文档。

如果来电findByFoo(null, "b"),则会返回没有属性stuff.in.nested.doc的文档,第二个是&#34; b&#34;。

有没有办法告诉查询忽略参数foo以防空白/空?

换句话说,我希望findByFoo("", "b")只返回参数bar为&#34; b&#34;的所有文档,忽略第​​一个参数。

由于参数数量可能会增加,因此编写多个方法不是一个可扩展的选项。

2 个答案:

答案 0 :(得分:0)

一个相对简单的解决方案是使用here所述的自定义存储库实现。对于我的示例代码,它会给出:

@Autowired
MongoTemplate mongoTemplate;

@Override
public List<MyDoc> findByCriteria(Map<String, String> requestCriteria) {

    Criteria criteria = new Criteria();

    // Foo
    if (requestCriteria.containsKey("foo")) {
        if (!StringUtils.isBlank(requestCriteria.get("foo"))) {
            criteria = criteria.and("stuff.in.nested.doc").is(requestCriteria.get("foo"));
        }
    }

    // Bar
    if (requestCriteria.containsKey("bar")) {
        if (!StringUtils.isBlank(requestCriteria.get("bar"))) {
            criteria = criteria.and("another.stuff.in.nested.doc").is(requestCriteria.get("bar"));
        }
    }

    return mongoTemplate.find(new Query(criteria), MyDoc.class, "mydoc");
}

另一个解决方案可能是使用QueryDSL(来自Marc Tarin的评论),我尚未对其进行测试。

答案 1 :(得分:0)

使用QueryDSL快速制作的解决方案:

public interface IMyDocDao extends MongoRepository<MyDoc, String>,
                                   QueryDslPredicateExecutor<MyDoc>, 
                                   QuerydslBinderCustomizer<MyDoc> {

    @Override
    default void customize(QuerydslBindings bindings, QMyDoc myDoc) { // QMyDoc is generated by QueryDSL at build time
        bindings.bind(MyDoc.class)
                .first((StringPath path, String value) -> { 
                   if (!value.isEmpty()) {
                       path.eq(value);
                   }
                });
    }
}

然后在你的控制器中注入一个IMyDocDao:

@RestController
public class MyDocController {

    @Autowire
    private IMyDocDao myDocDao;

    @GetMapping("myDoc/search/query")
    public List<MyDoc> query(@QuerydslPredicate(root = MyDoc.class) Predicate predicate) {
        return myDocDao(predicate);
}

GET .../myDoc/search/query?stuff.in.nested.doc=a&another.stuff.in.nested.doc=b应该返回预期的结果(尽管没有经过测试)。