Java List to Reactor Flux to Identity Map
Java List to Reactor Flux to Identity Map
我正在尝试实现一些简单的 Spring Boot GraphQL BatchMapping。
@BatchMapping
接收一个 List<Book>
然后调用一个 @Repository
并将结果转换为 Map<Book, Author>
。我正在努力使用 Reactor 的 Flux
和 Mono
.
@BatchMapping
Mono<Map<Book, Author>> author(List<Book> books) {
List<String> authorIds = books.stream().map(book -> book.authorId).toList();
Flux<Author> authors = authorRepository.findAllById(authorIds);
return authors.mapToTheBooksInTheCorrectOrder???();
}
每个Book
有一个Author
,但是多个Book
可以有相同的Author
。
我想return一个Map
(更准确地说是一个Mono<Map>
),其中键是每个Book
,值为对应的Author
.
您可以假设 Flux<Author>
中的 Author
(return 由 authorRepository.findAllById
编辑)是唯一的, 和 returned Author
与 List<Book>
中的 authorId
具有相同的顺序(第一次出现):
book1 = { id: "1", name: "A Scanner Darkly", authorId = "2" }
book2 = { id: "2", name: "High Fidelity", authorId = "1" }
book3 = { id: "3", name: "The Man In The High Castle", authorId = "2" }
将导致:
authors = [
{ id: "2", name: "Philip K. Dick" }
{ id: "1", name: "Nick Hornby" }
]
换句话说:
- 为
List<Book>
中的每个条目在 Map
中创建一个键
- 然后从
Flux<Author>
中获取匹配值
该方法的结果应该是(对于这个例子):
{
book1 : author2,
book2 : author1,
book3 : author2
}
全部包裹在 Mono<Map>
.
内
如果您在使用 Flux
和 Mono
时遇到困难,您可以使用 collectList()
运算符来获得 List<Author>
。例如:
return authorRepository
.findAllById(authorIds)
.collectList() // Mono<List<Author>>
.map(authors -> /* Use authors + books to get a Map<Book, Author> */);
这样做的好处是您可以使用 map()
运算符并使用您可能更熟悉的 List<Author>
和 List<Book>
类型。
就我个人而言,我什至建议使用 collectMap()
运算符并创建一个 Map
,其中作者的 ID 作为键,Author
作为 [= 的值21=]。这使得为每个 Book
检索相关的 Author
对象变得更加容易,因为这样您就可以使用 authorIdMap.get(book.getAuthorId())
。例如:
return authorRepository
.findAllById(authorIds)
.collectMap(Author::getId) // Mono<Map<String, Author>>
.map(authorIdMap -> /* Use authorIdMap + books to get a Map<Book, Author> */);
在这种情况下,authorIdMap
将是 Map<String, Author>
。
如果您不想在 map()
函数中使用常规 for-loop/streams,您也可以为此使用反应流。为此,您首先需要创建一个 Flux<Book>
,然后您可以再次使用 collectMap()
运算符,但这次的键将是 Book
对象,而值将是相应的 Author
对象。
return authorRepository
.findAllById(authorIds)
.collectMap(Author::getId) // Mono<Map<String, Author>>
.flatMap(authorIdMap -> Flux
.fromIterable(books) // Flux<Book>
.collectMap(identity(), book -> authorIdMap.get(book.getAuthorId()))); // Mono<Map<Book, Author>>
在这种情况下,您需要使用 flatMap()
而不是 map()
,因为该函数将 return 反应流而不是普通对象。
此外,要将当前对象用作 collectMap()
运算符中的键,您可以编写 collectMap(book -> book, ...)
。但是,编写这些 x -> x
lambda 的一种更简洁的方法是使用 Function.identity()
(如果使用静态导入,则使用 identity()
)。
我正在尝试实现一些简单的 Spring Boot GraphQL BatchMapping。
@BatchMapping
接收一个 List<Book>
然后调用一个 @Repository
并将结果转换为 Map<Book, Author>
。我正在努力使用 Reactor 的 Flux
和 Mono
.
@BatchMapping
Mono<Map<Book, Author>> author(List<Book> books) {
List<String> authorIds = books.stream().map(book -> book.authorId).toList();
Flux<Author> authors = authorRepository.findAllById(authorIds);
return authors.mapToTheBooksInTheCorrectOrder???();
}
每个Book
有一个Author
,但是多个Book
可以有相同的Author
。
我想return一个Map
(更准确地说是一个Mono<Map>
),其中键是每个Book
,值为对应的Author
.
您可以假设 Flux<Author>
中的 Author
(return 由 authorRepository.findAllById
编辑)是唯一的, 和 returned Author
与 List<Book>
中的 authorId
具有相同的顺序(第一次出现):
book1 = { id: "1", name: "A Scanner Darkly", authorId = "2" }
book2 = { id: "2", name: "High Fidelity", authorId = "1" }
book3 = { id: "3", name: "The Man In The High Castle", authorId = "2" }
将导致:
authors = [
{ id: "2", name: "Philip K. Dick" }
{ id: "1", name: "Nick Hornby" }
]
换句话说:
- 为
List<Book>
中的每个条目在Map
中创建一个键
- 然后从
Flux<Author>
中获取匹配值
该方法的结果应该是(对于这个例子):
{
book1 : author2,
book2 : author1,
book3 : author2
}
全部包裹在 Mono<Map>
.
如果您在使用 Flux
和 Mono
时遇到困难,您可以使用 collectList()
运算符来获得 List<Author>
。例如:
return authorRepository
.findAllById(authorIds)
.collectList() // Mono<List<Author>>
.map(authors -> /* Use authors + books to get a Map<Book, Author> */);
这样做的好处是您可以使用 map()
运算符并使用您可能更熟悉的 List<Author>
和 List<Book>
类型。
就我个人而言,我什至建议使用 collectMap()
运算符并创建一个 Map
,其中作者的 ID 作为键,Author
作为 [= 的值21=]。这使得为每个 Book
检索相关的 Author
对象变得更加容易,因为这样您就可以使用 authorIdMap.get(book.getAuthorId())
。例如:
return authorRepository
.findAllById(authorIds)
.collectMap(Author::getId) // Mono<Map<String, Author>>
.map(authorIdMap -> /* Use authorIdMap + books to get a Map<Book, Author> */);
在这种情况下,authorIdMap
将是 Map<String, Author>
。
如果您不想在 map()
函数中使用常规 for-loop/streams,您也可以为此使用反应流。为此,您首先需要创建一个 Flux<Book>
,然后您可以再次使用 collectMap()
运算符,但这次的键将是 Book
对象,而值将是相应的 Author
对象。
return authorRepository
.findAllById(authorIds)
.collectMap(Author::getId) // Mono<Map<String, Author>>
.flatMap(authorIdMap -> Flux
.fromIterable(books) // Flux<Book>
.collectMap(identity(), book -> authorIdMap.get(book.getAuthorId()))); // Mono<Map<Book, Author>>
在这种情况下,您需要使用 flatMap()
而不是 map()
,因为该函数将 return 反应流而不是普通对象。
此外,要将当前对象用作 collectMap()
运算符中的键,您可以编写 collectMap(book -> book, ...)
。但是,编写这些 x -> x
lambda 的一种更简洁的方法是使用 Function.identity()
(如果使用静态导入,则使用 identity()
)。