【问题标题】:Is there any way to implement pagination in spring webflux and spring data reactive有没有办法在spring webflux和spring data react中实现分页
【发布时间】:2018-02-06 01:09:43
【问题描述】:

我正在尝试理解 spring 5 的反应部分。我创建了简单的休息端点,用于使用 spring web-flux 和 spring data reactive (mongo) 查找所有实体,但看不到如何实现分页。

这是我在 Kotlin 中的简单示例:

@GetMapping("/posts/")
fun getAllPosts() = postRepository.findAll()

这是否意味着响应式端点不需要分页? 是否有某种方法可以使用此堆栈从服务器端实现分页?

【问题讨论】:

标签: spring mongodb kotlin spring-data-mongodb spring-webflux


【解决方案1】:

Flux提供skiptake方法来获得分页支持,你也可以使用filtersort对结果进行过滤和排序。 下面的过滤和排序不是一个很好的例子,但是使用skipPageable作为第二个参数没有什么不同。

以下代码对我有用。

@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);
}

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

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

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

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")))

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

 find using query: { "title" : { "$regularExpression" : { "pattern" : ".*title.*", "options" : ""}}} fields: Document{{title=1}} for class: class com.example.demo.Post in collection: post

//other logging...

 find using query: { "title" : { "$regularExpression" : { "pattern" : ".*title.*", "options" : ""}}} fields: Document{{title=1}} for class: class com.example.demo.Post in collection: post

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

检查example codes

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

【讨论】:

  • 这不会比Mono&lt;Page&lt;T&gt;&gt;消耗更多的资源(内存和CPU)吗?
  • 这对于包含数千个文档的大型集合来说效率非常低。最好在数据库端进行过滤,然后加载所有记录并在代码中过滤。
  • @Mavo 我认为如果 db 驱动程序完全实现 ReactiveStrreams 不会有性能问题,它应该将这些操作直接委托给底层 db。
  • 我已经测试了这两个选项,通量过滤比在 MongoDB 上正确运行查询要慢得多。
  • @OCPi 我认为您是对的,该操作可以逐个迭代结果并在数据库端返回您想要的结果。我认为这有点像在 JPA 中返回 Stream 结果,它将使用 JDBC 游标来迭代 DB 中的数据。它应该从不加载内存中的所有数据并过滤它们。
【解决方案2】:

Spring Data 中的响应式支持不提供 Page 返回类型的方法。尽管如此,Pageable 参数在将limitoffset 传递给驱动程序和存储本身的方法签名中得到支持,返回一个发出请求范围的Flux&lt;T&gt;

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

如需了解更多信息,请查看当前的Reference Documentation for 2.0.RC2Spring Data Examples

【讨论】:

    猜你喜欢
    • 2020-02-18
    • 2019-09-23
    • 2020-08-25
    • 2014-03-14
    • 2021-09-10
    • 2018-06-30
    • 1970-01-01
    • 2016-11-15
    • 1970-01-01
    相关资源
    最近更新 更多