【问题标题】:Passing array of reg expressions to spring based mongo @Query将正则表达式数组传递给基于spring的mongo @Query
【发布时间】:2016-08-04 16:13:33
【问题描述】:

我正在使用带有 mongodb 的 Spring Boot。我扩展了 PagingAndSortingRepository 存储库并添加了以下功能

@Query("{'title':{ $nin: [?0]}}")
List<Item> findItem(String[] exclude);

我希望能够向它传递一组正则表达式,例如 /dog/、/cat/、/horse/,以排除任何可能在其标题中包含其中一个的项目。

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

【问题讨论】:

  • 您似乎将手指放在了无法通过“标准”查询方法或 @Query 注释(截至今天)直接解决的 案例上。您是否打算在控制器中使用您的存储库实例?如果是这样,我可能会有一个想法。
  • 是的,我在 @RestController 实例中使用 repo。我正在考虑将数组转换为单个正则表达式并改用 $regex ,但这不是一个非常干净的解决方案。
  • 你的单个正则表达式可能包含管道,我很确定 Spring 对 URL 中的管道响应良好。
  • 你可能是对的。还有其他建议吗?

标签: spring spring-data-mongodb


【解决方案1】:

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

在你的控制器中添加这样的东西:

@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;
}

您当然可以添加 Pageable 参数并返回 Page 而不是 List。


编辑:如果您将 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);
    }
}

控制器方法:

@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;
    }


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

public interface ItemRepository extends CrudRepository<Item, String>,
    QueryDslPredicateExecutor<Item> {
    ...
}

控制器方法:

@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;
    }

活页夹类:

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);
}

}


编辑:为了详尽无遗以及那些不想听到 Querysl 的人。使用Spring Data Mongodb Reference中提出的解决方案。

定义自定义存储库接口:

interface ItemRepositoryCustom {

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

}

定义自定义存储库实现(Impl 需要后缀!):

public class ItemRepositoryImpl implements ItemRepositoryCustom {

    @Autowired
    private MongoOperations operations;

    @Override
    public Page<Item> findByNameRegexNotIn(Collection<String> names, Pageable pageable) {
        String pattern = StringUtils.collectionToDelimitedString(names, "|");
        // this time we use org.springframework.data.mongodb.core.query.Query instead of Querydsl predicates
        Query query = Query.query(where("name").regex(pattern).not()).with(pageable);

        List<Item> items = operations.find(query, Item.class);
        Page<Item> page = new PageImpl<>(items, pageable, items.size());

        return page;
    }

}

现在只需扩展 ItemRepositoryCustom:

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

...

}

你就完成了!

【讨论】:

  • 谢谢!会试一试并回复您。
  • @jvence 我用另一种解决方案编辑了我的答案(感谢你,我发现了有趣的事情;))
  • @jvence 还有第三个(也是最后一个)替代方案。
  • 谢谢,我最终使用了第一种方法,它似乎运行良好。我认为 Spring 应该使用 @Query 方法来支持这一点。
  • 那我建议你在 Spring Data MongoDB JIRA 上打开一个特性请求。
【解决方案2】:

您可以将java.util.regex.Pattern[] 传递给该方法。这将在后台转换为正则表达式数组:

@Query("{'title':{ $nin: ?0}}")
List<Item> findItem(Pattern[] exclude);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-01-10
    • 2012-07-14
    • 1970-01-01
    • 2018-02-28
    • 2021-12-06
    • 1970-01-01
    • 1970-01-01
    • 2013-04-19
    相关资源
    最近更新 更多