将reg表达式数组传递给基于spring的mongo@Query

将reg表达式数组传递给基于spring的mongo@Query,spring,spring-data-mongodb,Spring,Spring Data Mongodb,我在mongodb中使用Spring boot。我扩展了分页和排序存储库,并添加了以下功能 @Query("{'title':{ $nin: [?0]}}") List<Item> findItem(String[] exclude); @Query(“{'title':{$nin:[?0]}}”) 列表findItem(字符串[]排除); 我希望能够向它传递一个正则表达式数组,例如/dog/、/cat/、/horse/,以排除标题中可能包含其中一个正则表达式的任何项目 上述函数

我在mongodb中使用Spring boot。我扩展了分页和排序存储库,并添加了以下功能

@Query("{'title':{ $nin: [?0]}}")
List<Item> findItem(String[] exclude);
@Query(“{'title':{$nin:[?0]}}”)
列表findItem(字符串[]排除);
我希望能够向它传递一个正则表达式数组,例如/dog/、/cat/、/horse/,以排除标题中可能包含其中一个正则表达式的任何项目


上述函数不起作用,因为排除已转换为字符串。如何传递正则表达式数组才能执行上述操作?

您可以通过在一个控制器方法中使用谓词来解决此问题

public interface ItemRepository extends CrudRepository<Item, String>,
    QueryDslPredicateExecutor<Item> {
    ...
}
向控制器中添加如下内容:

@RequestMapping(value="/search/findByNameRegexNotIn", method = RequestMethod.GET)
@ResponseBody
public List<Item> findByNameRegexNotIn(@RequestParam(name = "name") List<String> names) {
    // build a query predicate
    BooleanBuilder predicate = new BooleanBuilder();  // comes from the Querydsl library
    for (String name : names) {
            predicate.and(QItem.item.name.contains(name).not()); // the QItem class is generated by Querydsl
    }

    List<Item> items = (List<Item>)repository.findAll(predicate);

    return items;
}
@RequestMapping(value=“/search/findByNameRegexNotIn”,method=RequestMethod.GET)
@应答器
公共列表findByNameRegexNotIn(@RequestParam(name=“name”)列表名称){
//构建查询谓词
BooleanBuilder谓词=新的BooleanBuilder();//来自Querydsl库
for(字符串名称:名称){
predicate.and(QItem.item.name.contains(name.not());//QItem类由Querydsl生成
}
List items=(List)repository.findAll(谓词);
退货项目;
}
当然,您可以添加一个Pageable参数并返回一个页面而不是列表


编辑:如果仅出于此目的使用Querydsl,另一种解决方案是覆盖查询参数的默认绑定

public interface ItemRepository extends CrudRepository<Item, String>,
    QueryDslPredicateExecutor<Item>, QuerydslBinderCustomizer<QItem> {

    @Override
    default public void customize(QuerydslBindings bindings, QItem item) {
        bindings.bind(item.name).all(
            (path, values) ->  path.matches(StringUtils.collectionToDelimitedString(values, "|")).not());
        // disable query on all parameters but the item name
        bindings.including(item.name);
        bindings.excludeUnlistedProperties(true);
    }
}
public interface ItemRepository扩展了crudepository,
QueryDslPredicateExecutor,QuerydslBinderCustomizer{
@凌驾
默认公共void自定义(QuerydslBindings绑定,QItem项){
bindings.bind(item.name).all(
(路径,值)->path.matches(StringUtils.collectionToDelimitedString(值“|”).not();
//禁用对除项目名称以外的所有参数的查询
绑定。包括(item.name);
绑定。排除未定义的属性(真);
}
}
控制器方法:

@RequestMapping(value="/search/query", method = RequestMethod.GET)
@ResponseBody
public List<Item> queryItems(
        @QuerydslPredicate(root = Item.class) Predicate predicate) {
        List<Item> items = (List<Item>)repository.findAll(predicate);

        return items;
    }
@RequestMapping(value="/search/query", method = RequestMethod.GET)
@ResponseBody
public List<Item> queryItems(
        @QuerydslPredicate(root = Item.class, bindings = ItemBinder.class) Predicate predicate) {
        List<Item> items = (List<Item>)repository.findAll(predicate);

        return items;
    }
@RequestMapping(value=“/search/query”,method=RequestMethod.GET)
@应答器
公共列表查询项(
@QueryDSL谓词(根=Item.class)谓词(谓词){
List items=(List)repository.findAll(谓词);
退货项目;
}

编辑:如果不想覆盖默认的QuerydslBinderCustomizer#customize,也可以实现自己的绑定并在控制器方法中指定它

public interface ItemRepository extends CrudRepository<Item, String>,
    QueryDslPredicateExecutor<Item> {
    ...
}
public interface ItemRepository扩展了crudepository,
QueryDSL谓词执行器{
...
}
控制器方法:

@RequestMapping(value="/search/query", method = RequestMethod.GET)
@ResponseBody
public List<Item> queryItems(
        @QuerydslPredicate(root = Item.class) Predicate predicate) {
        List<Item> items = (List<Item>)repository.findAll(predicate);

        return items;
    }
@RequestMapping(value="/search/query", method = RequestMethod.GET)
@ResponseBody
public List<Item> queryItems(
        @QuerydslPredicate(root = Item.class, bindings = ItemBinder.class) Predicate predicate) {
        List<Item> items = (List<Item>)repository.findAll(predicate);

        return items;
    }
@RequestMapping(value=“/search/query”,method=RequestMethod.GET)
@应答器
公共列表查询项(
@QueryDSL谓词(根=Item.class,绑定=ItemBinder.class)谓词){
List items=(List)repository.findAll(谓词);
退货项目;
}
活页夹类别:

class ItemBinder implements QuerydslBinderCustomizer<QItem> {

@Override
public void customize(QuerydslBindings bindings, QItem item) {
    bindings.bind(item.name).all(
            (path, values) ->  path.matches(StringUtils.collectionToDelimitedString(values, "|")).not()
    );
    bindings.including(item.name);
    bindings.excludeUnlistedProperties(true);
}
class ItemBinder实现QuerydslBinderCustomizer{
@凌驾
public void自定义(QuerydslBindings绑定,QItem项){
bindings.bind(item.name).all(
(路径,值)->path.matches(StringUtils.collectionToDelimitedString(值“|”).not()
);
绑定。包括(item.name);
绑定。排除未定义的属性(真);
}
}


编辑:为了精疲力尽和那些不想听Querysl的人。使用中提出的解决方案

定义自定义存储库接口:

interface ItemRepositoryCustom {

    public Page<Item> findByNameRegexIn(Collection<String> names, Pageable page);

}
接口项RepositoryCustom{
公共页面findByNameRegexIn(集合名称,可分页页面);
}
定义自定义存储库实现(需要Impl postfix!):

公共类ItemRepositoryImpl实现ItemRepositoryCustom{
@自动连线
私人运营;
@凌驾
公共页findByNameRegexNotIn(集合名称,可分页){
字符串模式=StringUtils.collectionToDelimitedString(名称“|”);
//这次我们使用org.springframework.data.mongodb.core.query.query代替Querydsl谓词
Query Query=Query.Query(其中(“name”).regex(pattern.not())。带有(pageable);
List items=operations.find(查询,Item.class);
Page Page=new PageImpl(items,pageable,items.size());
返回页面;
}
}
现在只需扩展ItemRepositoryCustom:

public interface ItemRepository extends MongoRepository<Item, String>, ItemRepositoryCustom {

...

}
公共接口ItemRepository扩展了MongoRepository、ItemRepositoryCustom{
...
}

你完了

似乎您已经将手指放在了“标准”查询方法或@query注释(截至今天)无法直接解决的问题上。您是否计划在控制器中使用存储库实例?如果是这样,我可能有个主意。是的,我正在@RestController实例中使用repo。我曾考虑将数组转换为单个正则表达式,并改用$regex,但这不是一个非常干净的解决方案。您的单个正则表达式可能包含管道,我非常确定Spring对URL中的管道响应良好。您可能是对的。还有其他建议吗?谢谢!将尝试一下,然后返回给您。@jvence我用另一种解决方案编辑了我的答案(多亏了您,我发现了一些有趣的事情;)@jvence和第三种(也是最后一种)解决方案。谢谢您,我最终使用了第一种方法,它似乎工作得很好。我认为Spring应该支持@Query方法,然后我建议您在Spring数据MongoDB上打开一个功能请求。