MongoRepository 动态查询 [英] MongoRepository dynamic queries

查看:29
本文介绍了MongoRepository 动态查询的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下问题.假设我有以下模型对象:

I have the following problem. Lets say I have the following model object:

class Person {
    String id;
    String firstName;
    String lastName;
    Map<String, String> properties;
}

在属性图中,您可以插入任何类型的属性,没有限制.

In the properties map, you can insert any kind of property, there are no constrains.

上述对象保存在一个 MongoDB 中,如下所示:

The above object is saved in a MongoDB which looks like this:

public interface PersonRepo extends MongoRepository<Person, String> {
}

当一个人被保存到存储库中时,Mapproperties 变平了.例如,如果我们有以下对象:

When a person is saved into the repository the Map<String, String> properties is flatten up. As an example, if we have the following object:

Person: {
    id := 1;
    firstName := John,
    lastName  := Doe,
    properties := {
        age: 42
    }
}

保存在 MongoRepository 中的文档如下:

the document saved in the MongoRepository will be the following:

Person: {
    id := 1;
    firstName := John,
    lastName  := Doe,
    age := 42
}

现在我的问题是我必须根据(例如)寻找对象,如果它们具有特定的属性.假设我想要定义了年龄属性的所有人员.一个重要的附加要求是我应该返回一个分页结果.

Now my problem is that I have to look for objects based on (for example), if they have a specific property or not. Lets say I want all Persons for which an age property has been defined. One important additional requirement is that I should return a paged result.

我试过使用

findAll(Example<Person> example, Pageable pageable)

但是由于某种原因这不起作用.我怀疑这是因为我的模型对象和 MongoDB 文档具有不同的结构.

But this does not work for some reason. I suspect that it's the fact that my model object and the MongoDB Document have different structures.

我也尝试过使用 QueryDsl(这里有一个例子:http://www.baeldung.com/queries-in-spring-data-mongodb)但也没有成功,而且对我来说这个解决方案也不是很优雅(必须维护生成的类等.另外我有一种感觉,因为我的 Map properties 对象成员,它不会工作.

I've also tried with the QueryDsl (here you have an example: http://www.baeldung.com/queries-in-spring-data-mongodb) but with no success either, and also to me this solution is not to elegant (having to mantain generated classes and alike. Also I have a feeling it will not work because of my Map<String, String> properties object member).

我想到的另一个足够优雅的解决方案是具有以下功能:

Another solution that came to my mind and would be elegant enough, is to have the following function:

@Query(value = "?0")
Page<Query> findByQuery(String query, Pageable pageable)

在这种情况下,我将能够手动构建查询,而不必对运行搜索所用的键进行硬编码.我现在的问题是,如何将查询值设置为我的第一个参数?使用上面显示的示例,我收到以下错误

In this case I would be able to manually construct the query and I wouldn't have to hardcode the key by which I run the search. My question now is, how can set the query value to be exactly my first parameter? With the example showned above I get the following error

java.lang.ClassCastException: java.lang.String cannot be cast to com.mongodb.DBObject

另一种解决方案是使用 mongoTemplate 并在给定一些 Criteria 的情况下进行查询,如下例所示:

One other solution would be to use mongoTemplate and query given some Criteria as in the following example:

    final Query query = new Query();
    query.addCriteria(Criteria.where("age").regex(".*"));

    mongoTemplate. find(query, Person.class);

这个解决方案的问题在于它返回一个对象列表而不是分页结果.如果我添加 query.with(new PageRequest(3, 2)); ,它也会返回一个特定的页面,但在这种情况下,我无法手动构建分页"结果,因为我不知道总数元素数量.

The problem with this solution is that it returns a list of objects instead for a paged result. It cal also return a specific page if I add query.with(new PageRequest(3, 2)); but in this case I cannot manually construct the "paged" result because I do not know the total number of elements.

你还有什么其他想法可以帮助我吗?

Do you have any other ideas that could help me?

提前致谢!

推荐答案

Bellow 是我想出的解决方案.所以简单回顾一下,我遇到的问题是,我无法在给定 Query 对象作为输入的情况下执行查询,以提高过滤条件的灵活性.结果证明解决方案很简单,我只需要仔细阅读文档:)

Bellow is the solution I've come up with. So just to recap, the problem that I had, was that I wan't able to execute a query given an Query object as input to have increased flexibility over the filtering criterias. The solution turned out to be quite simple, I just had to carefully read the documentation :).

  1. 步骤

扩展 MongoRepository 并添加您的自定义函数:

Extends MongoRepository and add your custom functions:

@NoRepositoryBean
public interface ResourceRepository<T, I extends Serializable> extends MongoRepository<T, I> {

    Page<T> findAll(Query query, Pageable pageable);
}

  1. 步骤

为此接口创建一个实现:

Create an implementation for this interface:

public class ResourceRepositoryImpl<T, I extends Serializable> extends SimpleMongoRepository<T, I> implements ResourceRepository<T, I> {

    private MongoOperations mongoOperations;
    private MongoEntityInformation entityInformation;

    public ResourceRepositoryImpl(final MongoEntityInformation entityInformation, final MongoOperations mongoOperations) {
        super(entityInformation, mongoOperations);

        this.entityInformation = entityInformation;
        this.mongoOperations = mongoOperations;
    }

    @Override
    public Page<T> findAll(final Query query, final Pageable pageable) {
        Assert.notNull(query, "Query must not be null!");

        return new PageImpl<T>(
                mongoOperations.find(query.with(pageable), entityInformation.getJavaType(), entityInformation.getCollectionName()),
                pageable,
                mongoOperations.count(query, entityInformation.getJavaType(), entityInformation.getCollectionName())
        );
    }
}

  1. 步骤

将您的实现设置为默认的 MongoRepository 实现:

Set your implementation as the default MongoRepository implementation:

@EnableMongoRepositories(repositoryBaseClass = ResourceRepositoryImpl.class)
public class MySpringApplication {
    public static void main(final String[] args) {
        SpringApplication.run(MySpringApplication.class, args);
    }
}

  1. 步骤

为您的自定义对象创建一个存储库:

Create a repository for your custom object:

public interface CustomObjectRepo extends ResourceRepository<CustomObject, String> {
}

现在,如果您有多个对象想要保存在 mongo 文档存储中,那么定义一个扩展您的 ResourceRepository 的接口就足够了(如步骤 4 中所示),您将拥有可用 Page;findAll(Query query, Pageable pageable) 自定义查询方法.我发现这个解决方案是我尝试过的最优雅的解决方案.

Now if you have multiple objects which you want to save in a mongo document store, it is enough to define an interface which extends your ResourceRepository (as seen in step 4), and you will have available the Page<T> findAll(Query query, Pageable pageable) custom query method. I have found this solution to be the most elegant of the solution I've tried.

如果您有任何改进建议,请与社区分享.

If you have any suggestions for improvements, please share them with the community.

问候,克里斯蒂安

这篇关于MongoRepository 动态查询的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆