【问题标题】:dynamic parametrized queries using Spring data mongodb使用 Spring 数据 mongodb 的动态参数化查询
【发布时间】:2015-11-12 13:57:41
【问题描述】:

我正在寻找一种动态创建参数化查询的方法。本质上,我想将查询与应用程序分离并使其可配置。

例如,我想创建一个带有参数的查询,例如

{ firstName: ?0 }

您可能知道,这在 Spring data mongodb 中使用接口是完全可行的:

interface MyQuery {

  @Query("{firstName: ?0}")
  public Person getByFirstName(final String name);
}

但这会在编译时结合我的查询,而我想在运行时更改它们。


但是我找不到动态使用这种机制的方法。在后台使用的特定类是StringBasedMongoQuery,并使用大量反射实用程序来确定查询、参数、返回类型等。我认为您可以使用 Groovy 管理其中的大部分,但是注释似乎是泡菜。

这让我觉得我选择了错误的方式来解决这个问题。


我自己只看到了几个选项:

  • 自己重新实现 Spring 对 mongo 的奇特查询解析(似乎需要做很多工作)
  • 自己实现穷人的查询参数替换。 (这不灵活,不会在空参数上产生正确的结果......)

我在这里不知所措,可惜我似乎无法独立使用StringBasedMongoQuery,它似乎与反射耦合。


更新:

我的建议在这里似乎毫无意义,因为我还注意到 Spring data mongodb 的 StringBasedMongoQuery 不支持带有可为空参数的“动态”查询;事实上,这是很合乎逻辑的,当参数为空时,很难从查询中删除部分内容,而且完全不可能做到这一点。

以下内容对这个问题有所说明:https://jira.spring.io/browse/DATAJPA-209

看来我可能的选择已经转移到:

  • 我们进行不同的查询,使用的查询取决于可用的参数。这可能会给维护带来噩梦。
  • 我们公开了一个 groovy 或其他 JVM 脚本,允许我们使用 Spring 或 mongodb Java 驱动程序中可用的 Criteria-esque API 之一,然后为我们构建查询。这样做的缺点是,想要配置查询的人现在必须至少了解 Java。
  • 我们以牺牲可读性为代价使查询在需要时为空值安全。

【问题讨论】:

    标签: mongodb dynamic parameters spring-data spring-data-mongodb


    【解决方案1】:

    我找到了一个比我在这篇文章中提出的建议更好、更简单的解决方案。我会告诉你我将如何解决这个问题以供其他人参考。

    虽然 mongodb 没有查询参数或类似的东西,但我们可以通过使用 mongodb 提供的一些其他相当独特的结构以及严格的结构来使事情变得更容易。我们可以坚持这种结构,因为它涉及用户的动态可配置查询。

    我们的结构很简单,如下。我们的基本查询结构如下所示:

    { $and: []}
    

    我们定义了一个基本的查询,它总是会被填充。这可以像空的 JS 对象一样简单。像这样,我们的查询变成了

    { $and: [{}] }
    

    所以,这只是查询所有内容。现在我们可以为每个可以是动态的条件定义一个子查询。如果满足条件,我们可以选择将此查询添加到$and。由于我们坚持将所有内容放在一个 and 构造中,因此我们知道查询的外观,并且我们不需要非常花哨的参数替换来获得非常灵活的东西以轻松工作。

    查询可以变成例如:

    { $and: [{}, {active: true}, {started: false}]}
    

    我们可以随时添加这些小子查询。

    【讨论】:

    • 我在这里得到你所拥有的东西并不安静。你能展示你的自定义 MongoRepository 界面吗?
    【解决方案2】:

    此方法采用参数映射及其值并基于它形成查询。该解决方案的明显缺点是形成的查询基于 AND。因此,如果您需要一个仅由逻辑 AND 组成的动态查询,那么这是可行的方法。我仍在处理具有所有逻辑操作的完全动态查询。用 Groovy 编写:

    Query buildSearchQuery(Map searchParams, List resultFields, int limit) {
    Query query = new Query()
    searchParams.each {
        if (it.getValue() != null && it.getValue() != '') {
            query.addCriteria(Criteria.where(it.getKey()).regex('^'+ it.getValue(), 'i'))
            }
        }
    
        resultFields.each {
            query.fields().include(it)
        }
        query.limit(limit)
    
        query
    }
    

    【讨论】:

      【解决方案3】:

      您可以解决此问题的另一种方法是使用 Example 对象...我正在利用 spring-data-mongodb 顺便说一句,所以不确定这是否适用于您...

      public interface PetRepository extends MongoRepository<Pet, String>{
      }
      

      ...

      @Service
      public class PetService {
      
      private Logger logger = LogManager.getLogger(PetService.class);
      
      @Autowired
      PetRepository petRepository;
      
      public List<Pet> findPetsByExample(String name, String sex, String color, Integer age){
          //Guard clauses omitted...
          Example<Pet> example = Example.of(new Pet(name, sex, color, age));
          return Lists.newArrayList(petRepository.findAll(example));
      }
      

      现在所做的是利用在 MongoRepository 中扩展的 QueryByExampleExecutor 类在后台将提供的示例宠物与您的文档内容进行比较。这只会查看我们的示例宠物上提供值的字段,并在比较中忽略 Null。您还可以包含自定义匹配器以执行进一步过滤。这是一些示例文档的链接:https://github.com/spring-projects/spring-data-examples/tree/master/mongodb/query-by-example

      【讨论】:

        猜你喜欢
        • 2014-06-30
        • 1970-01-01
        • 1970-01-01
        • 2019-12-14
        • 2014-08-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多