首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MongoRepository动态查询

MongoRepository动态查询
EN

Stack Overflow用户
提问于 2017-05-24 07:40:29
回答 4查看 8.3K关注 0票数 3

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

代码语言:javascript
复制
class Person {
    String id;
    String firstName;
    String lastName;
    Map<String, String> properties;
}

在属性映射中,您可以插入任何类型的属性,没有约束。

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

代码语言:javascript
复制
public interface PersonRepo extends MongoRepository<Person, String> {
}

当一个人被保存到存储库中时,Map<String, String> properties就会扁平化。例如,如果我们有以下对象:

代码语言:javascript
复制
Person: {
    id := 1;
    firstName := John,
    lastName  := Doe,
    properties := {
        age: 42
    }
}

保存在MongoRepository中的文档如下:

代码语言:javascript
复制
Person: {
    id := 1;
    firstName := John,
    lastName  := Doe,
    age := 42
}

现在我的问题是,如果对象是否具有特定属性,则必须基于(例如)查找对象。让我说,我想要所有已经为其定义了年龄财产的人。一个重要的附加要求是,我应该返回一个分页的结果

我试过用

代码语言:javascript
复制
findAll(Example<Person> example, Pageable pageable)

但由于某种原因,这种做法行不通。我怀疑我的模型对象和MongoDB文档有不同的结构。

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

我想到的另一个解决方案是具有以下功能,并且非常优雅:

代码语言:javascript
复制
@Query(value = "?0")
Page<Query> findByQuery(String query, Pageable pageable)

在这种情况下,我可以手动构造查询,也不必硬编码运行搜索的密钥。我现在的问题是,如何才能将查询值精确地设置为我的第一个参数?在上面显示的示例中,我得到以下错误

代码语言:javascript
复制
java.lang.ClassCastException: java.lang.String cannot be cast to com.mongodb.DBObject

另一个解决方案是使用mongoTemplateCriteria查询,如下面的示例所示:

代码语言:javascript
复制
    final Query query = new Query();
    query.addCriteria(Criteria.where("age").regex(".*"));

    mongoTemplate. find(query, Person.class);

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

你还有其他能帮我的主意吗?

提前感谢!

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2017-07-31 09:22:02

贝娄是我想出的解决办法。因此,简单地回顾一下,我遇到的问题是,我无法执行给定查询对象作为输入的查询,从而提高了过滤标准的灵活性。解决方案非常简单,我只需仔细阅读文档:)。

  1. 步骤

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

代码语言:javascript
复制
@NoRepositoryBean
public interface ResourceRepository<T, I extends Serializable> extends MongoRepository<T, I> {

    Page<T> findAll(Query query, Pageable pageable);
}
  1. 步骤

为该接口创建一个实现:

代码语言:javascript
复制
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实现:

代码语言:javascript
复制
@EnableMongoRepositories(repositoryBaseClass = ResourceRepositoryImpl.class)
public class MySpringApplication {
    public static void main(final String[] args) {
        SpringApplication.run(MySpringApplication.class, args);
    }
}
  1. 步骤

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

代码语言:javascript
复制
public interface CustomObjectRepo extends ResourceRepository<CustomObject, String> {
}

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

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

你好,克里斯蒂安

票数 3
EN

Stack Overflow用户

发布于 2017-07-27 20:08:57

我最近也遇到了类似的情况。使用Clazz代替我的域类,下面是我所做的工作:

代码语言:javascript
复制
long count = mongoTemplate.count(query, clazz.class);
query.with(pageable);
List<Clazz> found = mongoTemplate.find(query, clazz.class);
Page<Clazz> page = new PageImpl<T>(found, pageable, count);

我使用的是spring starter mongodb:1.5.5和Query + MongoTemplate处理分页。因此,首先,我得到了与查询匹配的所有文档的完整计数。然后,我再次使用peageable进行搜索,搜索再次跳过和限制(我知道,效率不高)。回到Controller时,您可以使用PagedResourcesAssembler's toResource( paging )方法将其封装在分页超链接中。

代码语言:javascript
复制
 public ResponseEntity search(@Valid @RequestBody MyParams myParams, Pageable pageable, PagedResourcesAssembler assembler){
    Page<Clazz> page= searchService.search(myParams, pageable, Clazz.class);
    PagedResources<Clazz> resources = assembler.toResource(page);
    return new ResponseEntity<>(resources, HttpStatus.OK);
}
票数 1
EN

Stack Overflow用户

发布于 2021-10-06 19:50:09

有一种非常简单的方法可以做到这一点,类似于您的代码:

代码语言:javascript
复制
@Query(value = "?0")
Page<Query> findByQuery(String query, Pageable pageable)

但是将查询作为BSONObject而不是字符串传递。

代码语言:javascript
复制
@Query("?0")
Page<Query> findByQuery(BSONObject query, Pageable pageable)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44151977

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档