有没有办法在spring webflux和spring数据反应中实现分页

Lon*_*iks 4 spring mongodb kotlin spring-data-mongodb spring-webflux

我试图了解弹簧5的反应部分.我创建了简单的休止端点,用于使用弹簧web-flux和弹簧数据反应(mongo)查找所有实体,但是没有看到任何方式如何实现分页.

这是我在Kotlin的简单例子:

@GetMapping("/posts/")
fun getAllPosts() = postRepository.findAll()
Run Code Online (Sandbox Code Playgroud)

这是否意味着被动端点不需要分页?是否有一些方法可以使用此堆栈从服务器端实现分页?

Chr*_*obl 10

Spring Data中的反应支持不提供Page返回类型的方法.尽管如此,Pageable参数是在传递方法签名支持limitoffset到驱动器,并且因此商店本身,返回一个Flux<T>发射请求的范围内.

Flux<Person> findByFirstname(String firstname, Pageable pageable);
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请查看2.0.RC2Spring数据示例的当前参考文档.


Han*_*tsy 6

助焊剂提供skiptake方法来获得分页支持,你也可以使用filtersort对结果进行过滤和排序。 下面的过滤器和排序不是一个很好的例子,但 useskipPageableas 2nd 参数没有什么不同。

以下代码对我有用。

@GetMapping("")
public Flux<Post> all(
//@RequestParam(value = "q", required = false) String q,
                      @RequestParam(value = "page", defaultValue = "0") long page,
                      @RequestParam(value = "size", defaultValue = "10") long size) {
    return this.postRepository.findAll()
        //.filter(p -> Optional.ofNullable(q).map(key -> p.getTitle().contains(key) || p.getContent().contains(key)).orElse(true))//(replace this with query parameters)
        .sort(comparing(Post::getCreatedDate).reversed())
        .skip(page * size).take(size);
}
Run Code Online (Sandbox Code Playgroud)

更新:底层驱动程序应负责以反应流方式处理结果。

正如您在 Christoph 的回答中看到的那样,如果使用findByXXX方法,Spring Data Mongo Reactive 提供了一个变体来接受pageable参数,但是findAll(反应式版本)不包含这样的变体skip如果您在后面的操作中执行真的需要分页功能。当切换到Flux而不是 List 时,将 Flux 中的数据想象成河流中的活水或管道中的石油,或者 twitter.com 中的推文。

我试图比较查询使用Pageale而不是在以下情况下。

@GetMapping("")
public Flux<Post> all(
//@RequestParam(value = "q", required = false) String q,
                      @RequestParam(value = "page", defaultValue = "0") long page,
                      @RequestParam(value = "size", defaultValue = "10") long size) {
    return this.postRepository.findAll()
        //.filter(p -> Optional.ofNullable(q).map(key -> p.getTitle().contains(key) || p.getContent().contains(key)).orElse(true))//(replace this with query parameters)
        .sort(comparing(Post::getCreatedDate).reversed())
        .skip(page * size).take(size);
}
Run Code Online (Sandbox Code Playgroud)

当启用日志记录logging.level.org.springframework.data.mongodb.core.ReactiveMongoTemplate=DEBUG并找到它们时,它们会为查询打印相同的日志。

this.postRepository.findByTitleContains("title")
                .skip(0)
                .limitRequest(10)
                .sort((o1, o2) -> o1.getTitle().compareTo(o2.getTitle()))


this.postRepository.findByTitleContains("title", PageRequest.of(0, 10, Sort.by(Sort.Direction.ASC, "title")))

Run Code Online (Sandbox Code Playgroud)

请记住,所有这些操作都应该委托给底层驱动程序(如果它已经实现了反应流规范)并在数据库端执行,而不是在应用程序端的内存中。

检查示例代码

我以上提供的早期示例代码可能不是一个很好的样本filtersort操作(MongoDB的本身提供了极大regularexpression的操作就可以了)。但是反应式变体中的分页与反应式流规范中的概念不太匹配。在拥抱 Spring 反应式堆栈时,大多数情况下,我们只是将我们的工作转移到新的 API 集合中。在我看来,实时更新和弹性响应场景可以更好地匹配Reactive,例如。将它与 SSE、Websocket、RSocket、application/stream+json(在新的 Spring 文档中缺少)协议等一起使用

  • 对于包含数千个文档的大型集合,这将非常低效。最好在 DB 端进行过滤,然后加载所有记录并在代码中过滤它们。 (4认同)
  • 这不会比 `Mono&lt;Page&lt;T&gt;&gt;` 消耗更多的资源(mem 和 CPU)吗? (2认同)