web-dev-qa-db-ja.com

Spring Reactive Programmingで2つのFlux(Object)からFluxまたはListを取得する方法は?

Spring Reactive Projectは初めてです。私のSpring Boot Controllerクラスには

Flux<House> ( list of all houses in the database) and Flux<Image>

与えられたFlux<Image>は、それぞれが独自の画像のコレクションを持っている家のリストのような、与えられた家の画像であるサービスレイヤーから来ています。つまり、Flux<House>を反復処理して家のIDを取得し、ImageでfindByHouseIdを呼び出してFlux<Image>を取得する必要があります。各画像にはhouseIdプロパティがあります。各画像オブジェクトには、文字列値「yes」または「no」のプロパティ「cover」と、「bedroom」などのさまざまな文字列値を持つ別のプロパティ「type」があります。集めたい

list of Flux<Image> like List<Flux<Image>> or List<List<Image>>

"カバー" == "はい" OR "タイプ" == "ベッドルーム"の画像のみを含む。これを達成する方法?プログラミングコードはこの質問に答えます。

以下はソリューションの一部として試みられましたが、この部分的なソリューションでさえ機能しません:

List<Flux<Image>> imagesList= new ArrayList<Flux<Image>>();
        Flux<House> houses = houseService.findAllHouses();

        houses.map(house ->  house.getId()).subscribe(id -> imageService.findByHouseId(id))
        .map(imageFlux ->imagesList.add(imageFlux));

これが唯一の方法でない限り、block()の呼び出し(リアクティブであるという利点を無効にする)を含まないソリューションを探していることに注意してください。

非反応的な状況では、これは私が欲しいものです:

List<House> houses  --> List of all houses
Map<String,List<Image>> mapOfImages  --> where key is houseId 

各家ごとに、ビューテンプレートで家を繰り返し処理しながら、その家の画像を簡単に取得できます。

これら(housesとmapOfImages)は次のようなモデルに渡されます

model.addAttribute("houses",houses);
model.addAttribute("mapOfImages",mapOfImages);

Thyemleafビューテンプレート内で、次のことができます。

<div data-th-each="house : ${houses}">
        <h3 data-th-text="${house.title}"></h3>
        <div data-th-each="image : ${mapOfImages.get(house.houseId)}">
          <h5 data-th-text="${image.fileName}"></h5>
          <h5 data-th-text="${image.type}"></h5>
        </div>
 </div>   

使用されているデータベースはMongodbであり、houseとimageという2つの独立したコレクションがあります。つまり、埋め込まれたコレクションはなく、画像をhouseに結び付けるのは画像のhouseIdプロパティだけです。

10
ace

基本的に、HouseオブジェクトのストリームをImageオブジェクトのストリームに変換します。

したがって、_Flux<Flux<T>>_(または_Flux<Mono<T>>_)を_Flux<T>_に変換するflatMap()を使用します。

_Mono<List<Image>> images = houseService.findAllHouses() // returns Flux<House>
  .flatMap(house -> imageService.findByHouseId(id)      // returns Flux<Image>
                        .filter(image -> "yes".equals(image.getCover()) && ... )) 
  .collectList();                                       //returns Mono<List<Image>>
_

とにかくimagesを単一の_Mono<ServerResponse>_オブジェクトに変換したいので、ここでcollectList()を使用しても問題ありません。

_return images.map(imageList -> ServerResponse.ok()
                                       .body(fromObject(imageList)));
_

また、 Project Reactorリファレンス について どの演算子をいつ使用するか を読むことをお勧めします。


編集:

したがって、代わりに_Mono<Map<String, Collection<Image>>_が必要です。私の答えは、ImageクラスがHouseへの参照を持っているかどうかによって異なります。そうでない場合でも問題ありませんが、答えはもっと冗長になります。

ImageHouse IDが含まれていない難しい方法を説明します。特定の家に属する画像のリストをリンクするsth。が必要です。この目的でクラスを定義するか、または単に_reactor.util.function.Tuple2_を使用できます。それがあれば、collectMap()を使用できます:

_Mono<Map<String, Collection<Image>>> images = houseService.findAllHouses()
     .flatMap(house -> imageService.findByHouseId(id)
                           .filter(...)
                           .map(image -> Tuples.of(id, image)))
     .collectMultiMap(Tuple -> Tuple.getT1(), 
                      Tuple -> Tuple.getT2());
_

もちろん、Houseへの参照がある場合は、map()を再度省略して、collectMultiMapを直接使用できます。

_...
    .collectMultiMap(image -> image.getHouseId(), image -> image);
_
8
MuratOzkan