如何在反应性Spring数据中应用分页?

时间:2017-09-23 21:54:26

标签: spring-data reactive-programming spring-data-mongodb

在Spring Data中,我们PagingAndSortingRepository继承自CrudRepository。在反应式Spring数据中,我们只有 ReactiveSortingRepository继承自ReactiveCrudRepository。 我们怎么能以反应的方式进行分页呢? 我们将来可以使用ReactivePagingAndSortingRepository进行此操作吗?

7 个答案:

答案 0 :(得分:8)

Reactive Spring Data MongoDB存储库在分页方面不提供分页,它是如何为命令式存储库设计的。在获取页面时,命令式分页需要其他详细信息。特别是:

  • 分页查询的返回记录数
  • (可选)如果返回的记录数为零或与页面大小匹配以计算总页数,则查询产生的记录总数

这两个方面都不符合高效,无阻塞资源使用的概念。等到收到所有记录(以确定第一个分页详细信息块)将消除通过响应数据访问获得的大部分好处。此外,执行计数查询相当昂贵,并且在您能够处理数据之前会增加延迟。

您仍然可以通过将PageablePageRequest)传递给存储库查询方法来自行获取数据块:

interface ReactivePersonRepository extends Repository<Person, Long> {

  Flux<Person> findByFirstnameOrderByLastname(String firstname, Pageable pageable);
}

Spring数据会通过将Pageable翻译为LIMITOFFSET来对查询应用分页。

参考文献:

答案 1 :(得分:3)

import com.thepracticaldeveloper.reactiveweb.domain.Quote;
import org.springframework.data.domain.Pageable;
import org.springframework.data.mongodb.repository.Query;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
import reactor.core.publisher.Flux;

public interface QuoteMongoReactiveRepository extends ReactiveCrudRepository<Quote, String> {

    @Query("{ id: { $exists: true }}")
    Flux<Quote> retrieveAllQuotesPaged(final Pageable page);
}

更多详情,you could check here

答案 2 :(得分:0)

我使用此方法为可能仍在寻找解决方案的任何人创建了服务:

@Resource
private UserRepository userRepository; //Extends ReactiveSortingRepository<User, String>

public Mono<Page<User>> findAllUsersPaged(Pageable pageable) {
        return this.userRepository.count()
                .flatMap(userCount -> {
                    return this.userRepository.findAll(pageable.getSort())
                            .buffer(pageable.getPageSize(),(pageable.getPageNumber() + 1))
                            .elementAt(pageable.getPageNumber(), new ArrayList<>())
                            .map(users -> new PageImpl<User>(users, pageable, userCount));
                });
    }

答案 3 :(得分:0)

我使用@ kn3l解决方案(不使用@Query)创建了另一种方法:

fun findByIdNotNull(page: Pageable): Flux< Quote>

它创建相同的查询而不使用@Query方法

答案 4 :(得分:0)

我遇到了同样的问题,最终采用了与上述类似的方法,但是在我使用查询DSL时,代码略有更改,下面是如果有人需要的示例。

@Repository
public interface PersonRepository extends ReactiveMongoRepository<Person, String>, ReactiveQuerydslPredicateExecutor<Person> {

    default Flux<Person> applyPagination(Flux<Person> persons, Pageable pageable) {
    return persons.buffer(pageable.getPageSize(), (pageable.getPageNumber() + 1))
        .elementAt(pageable.getPageNumber(), new ArrayList<>())
        .flatMapMany(Flux::fromIterable);
    }

}


public Flux<Person> findAll(Pageable pageable, Predicate predicate) {
    return personRepository.applyPagination(personRepository.findAll(predicate), pageable);
}

答案 5 :(得分:0)

正在寻找一些关于反应式可分页存储库的想法我看到了会导致可怕的样板代码的解决方案,所以我最终得到了这个(在现实生活中还没有尝试过,但应该可以正常工作,或者它可以为您提供灵感解决方案)

那么……让我们用这样的方法创建一个全新的工具箱类

    public static 
           <R extends PageableForReactiveMongo<S, K>, S, T, K> Mono<Page<T>>
           pageableForReactiveMongo(Pageable pageable, 
                                             R repository, Class<T> clazzTo) {
        return repository.count()
                .flatMap(c ->
                        repository.findOderByLimitedTo(pageable.getSort(),
                                              pageable.getPageNumber() + 1)
                                .buffer(pageable.getPageSize(), (pageable.getPageNumber() + 1))
                                .elementAt(pageable.getPageNumber(), new ArrayList<>())
                                .map(r -> mapToPage(pageable, c, r, clazzTo))
                );
    }

它也需要类似的东西:

    private static <S, T> Page<T> mapToPage(Pageable pageable, Long userCount, Collection<S> collection, Class<T> clazzTo) {
        return new PageImpl<>(
                collection.stream()
                        .map(r -> mapper.map(r, clazzTo))
                        .collect(Collectors.toList())
                , pageable, userCount);
    }

然后我们还需要一个抽象层来包装反应式存储库

public interface PageableForReactiveMongo<D, K> extends ReactiveMongoRepository<D, K> {
    Flux<D> findOderByLimitedTo(Sort sort, int i);
}

让它在 spring 实例化

@Repository
interface ControllerRepository extends PageableForReactiveMongo<ControllerDocument, String> {
}

最后像那样多次使用它

public Mono<Page<Controller>> findAllControllers(Pageable pageable) {
    return getFromPageableForReactiveMongo(pageable, controllerRepository, Controller.class);
}

这就是你的代码的样子:) 请告诉我它是否正常,或者帮助我做一些事情

答案 6 :(得分:-1)

public Mono<Page<ChatUser>> findByChannelIdPageable(String channelId, Integer page, Integer size) {
    Pageable pageable = PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "chatChannels.joinedTime"));
    Criteria criteria = new Criteria("chatChannels.chatChannelId").is(channelId);
    Query query = new Query().with(pageable);
    query.addCriteria(criteria);
    Flux<ChatUser> chatUserFlux = reactiveMongoTemplate.find(query, ChatUser.class, "chatUser");
    Mono<Long> countMono = reactiveMongoTemplate.count(Query.of(query).limit(-1).skip(-1), ChatUser.class);
    return Mono.zip(chatUserFlux.collectList(),countMono).map(tuple2 -> {
        return PageableExecutionUtils.getPage(
                tuple2.getT1(),
                pageable,
                () -> tuple2.getT2());
    });
}