将Flux的结果与Mono的结果相结合

时间:2017-04-19 21:48:19

标签: spring-webflux project-reactor reactive-streams

我开始使用Project reactor和一个我很难挣扎的地方,我怎么把Mono和Flux的东西结合起来。这是我的用例:

public interface GroupRepository {
       Mono<GroupModel> getGroup(Long groupId);
}

public interface UserRepository {
       Flux<User> getUsers(Set<Long> userIds);   
}

Mono<GroupModel> groupMono = getGroup(groupId);
Flux<User> userFlux = getUsers(Set<Long> users);
//run above instrtuction in parallel and associate user to group.

现在我想要实现的是:

如何组合UserFlux的响应并将这些用户与该组相关联,例如group.addUsers(userfromFlux)。

有人可以帮助您组合来自userFlux和groupMono的结果。我想我使用像Zip这样的东西,然后它从源头做一对一的映射。就我而言,我需要做1到N的映射。在这里,我有一个组,但我需要添加到该组的多个用户。返回Mono<List<Users>然后使用单声道的zip运算符并提供这里提到的组合器是一个好主意
 public static <T1, T2, O> Flux<O> zip(Publisher<? extends T1> source1, Publisher<? extends T2> source2, final BiFunction<? super T1, ? super T2, ? extends O> combinator)

3 个答案:

答案 0 :(得分:3)

我认为Flux.combineLatest静态方法可以帮助您:由于您的Mono只发出1个元素,因此该元素将始终与Flux中的每个传入值相结合。

Flux.combineLatest(arr -> new Combination((GroupModel) arr[0], (User) arr[1]),
                   groupMono, userFlux);

答案 1 :(得分:2)

从1到N的映射听起来类似于我在这里给出的答案:

Can you Flux.zip a mono and a flux and and repeat the mono value for every flux value?

万一该链接断开,这又是答案。我认为此方法不会具有良好的性能,因为每次都会重新计算单声道。为了获得更好的性能,如果您的Mono被慢速操作包围了,那么最好有一些缓存层。

假设您有一个通量和一个这样的单声道:

 // a flux that contains 6 elements.
 final Flux<Integer> userIds = Flux.fromIterable(List.of(1,2,3,4,5,6));

 // a mono of 1 element.
 final Mono<String> groupLabel = Mono.just("someGroupLabel");

首先,我将向您展示尝试压缩我尝试过的2的错误方式,我想其他人会尝试:

 // wrong way - this will only emit 1 event 
 final Flux<Tuple2<Integer, String>> wrongWayOfZippingFluxToMono = userIds
         .zipWith(groupLabel);

 // you'll see that onNext() is only called once, 
 //     emitting 1 item from the mono and first item from the flux.
 wrongWayOfZippingFluxToMono
         .log()
         .subscribe();

wrong way

 // this is how to zip up the flux and mono how you'd want, 
 //     such that every time the flux emits, the mono emits. 
 final Flux<Tuple2<Integer, String>> correctWayOfZippingFluxToMono = userIds
         .flatMap(userId -> Mono.just(userId)
                 .zipWith(groupLabel));

 // you'll see that onNext() is called 6 times here, as desired. 
 correctWayOfZippingFluxToMono
         .log()
         .subscribe();

enter image description here

答案 2 :(得分:0)

为其他人添加答案,我使用了Flux.zip(groupMono, userMono(holding list of users), this::biFunctionToPopulateGroupWithUsers)。我使用这种方法而不是@Simon的建议,因为持有用户的基础组是HashSet,并且以被动方式添加用户将不是线程安全的。但是,如果你有一个线程安全的数据结构,我会使用@Simon的建议。