简体   繁体   中英

combine multiple Mono<List<Item>> into one

I'm currently working on a project that involves a bit of reactive programming.

I have 4 different reactive repositories from which I get 4 different Mono<List<SomeType>> in return respectively. The goal is to combine them into a single Mono<List<GeneralType>> in order to incorporate that into a custom Response to return within a ResponseEntity.ok() . I have already taken care of creating a GeneralType and was successful in converting a single Mono<List<SomeType>> , however, made no further progress.

All repositories have a similar signature:

public Mono<List<SomeType>> findAllByUserId(UUID userId)

The field in my Response that incorporates all different lists as a single one:

private Mono<List<GeneralType>> items;

What my method looks like so far:

public Mono<List<GeneralType>> combineMonos(UUID userId) {
    Mono<List<GeneralType>> combo1 = reactiveRepository.findAllByUserId(userId)
        .map(list -> list.stream()
            .map(GeneralType::new)
            .collect(Collectors.toList()));
    return combo1; // works just fine
}

All the other lists have pretty much the same approach, but putting them together into a single Mono<List> is a problem.

I've tried the following:

return Flux.merge(combo1.flatMapMany(Flux::fromIterable), combo2.flatMapMany(Flux::fromIterable)).collectList();

But with that, the IDE urges to change the return type to Flux<Object> . Also, some lists can be empty, so I'm not sure if zip() is an option here. I've read that it will return everything as empty if at least a single result is empty.

So the question is how can that be done in an efficient way without block() everywhere?

Merge connects to all the data sources eagerly. So as and when data is emitted from the any of the sources, it would be passed to the downstream pipeline. Order in the resulting list is based on when the item was emitted.

Zip method collects the data from sources and places them inside an object (Tuple – something like a box) and passes to the downstream. Zip will work as long as all the sources emit data. Any of the sources completes/throws error, it will stop.


I assumed your individual methods are working fine. Your question is related to merging the results into a single list.

private Mono<List<String>> getList1(){
    return Mono.just(List.of("a", "b", "c"));
}

private Mono<List<String>> getList2(){
    return Mono.just(Collections.emptyList());
}

private Mono<List<String>> getList3(){
    return Mono.just(List.of("A", "B", "C"));
}


    Flux.merge(getList1(), getList2(), getList3())
            .flatMapIterable(Function.identity())
            .collectList()
            .subscribe(System.out::println);  // [a, b, c, A, B, C]

Reference: http://www.vinsguru.com/reactive-programming-reactor-combining-multiple-sources-of-flux-mono/

A Mono::zip will asynchronously combine the three publishers together which I think is the best solution.

Otherwise it is a pretty straightforward problem:

Mono<List<String>> m1 = Mono.just(Arrays.asList(new String[]{"A", "B", "C"}));
Mono<List<Character>> m2 = Mono.just(Arrays.asList(new Character[]{'a', 'b', 'c'}));
Mono<List<Integer>> m3 = Mono.just(Arrays.asList(new Integer[]{1, 2, 3}));
Mono.zip(m1, m2, m3)
        .map(tuple3->{
                List<Combined> c = new ArrayList<>();
                int size = tuple3.getT1().size();
                for ( int i=0; i < size; ++i ) {
                    c.add(new Combined(tuple3.getT1().get(i), tuple3.getT2().get(i), tuple3.getT3().get(i)));
                }
                return c;
        })
        .subscribe(System.out::println);
// [Combined(s=A, c=a, i=1), Combined(s=B, c=b, i=2), Combined(s=C, c=c, i=3)]

For completeness sake:

@Data
@AllArgsConstructor
class Combined {
    String s;
    Character c;
    Integer i;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM