将Mongo Collection中的几个Flux合并为一个

时间:2017-11-06 12:31:03

标签: java spring mongodb spring-boot project-reactor

我对弹簧反应式编程有点新意。我目前正在使用spring-boot-starter-webflux:2.0.0.M5开发一个应用程序。

我有一个Foodtruck mongodb模型,其中包含菜单:

@Document(collection = "Foodtruck")
@lombok.Getter
@lombok.Setter
@lombok.NoArgsConstructor
@lombok.AllArgsConstructor
public class Foodtruck {
  @Id
  private String id;

  @URL
  private String siteUrl;

  @NotBlank
  private String name;

  private String description;

  @NotBlank
  private String address;

  private List<Menu> menus;

  @JsonIgnore
  private GridFS image;
}

以下是菜单的模型:

@lombok.Getter
@lombok.Setter
@lombok.NoArgsConstructor
@lombok.AllArgsConstructor
@Document(collection = "menus")
public class Menu {

  @Id
  private String id;

  private List<DayOfWeek> days;

  @NotBlank
  private String label;

  private String description;

  private Double price;

  private List<Dish> dishes;

  @JsonIgnore
  private GridFS image;
}

要获取我的所有菜单,我首先需要获取所有餐馆,然后合并所有获得的 Flux ,并通过我的休息控制器返回。

以下是我从其余资源调用的服务:

@Service
public class MenuServiceImpl implements MenuService {

  FoodtruckService foodtruckService;

  public MenuServiceImpl(FoodtruckService foodtruckService) {
    this.foodtruckService = foodtruckService;
  }

  @Override
  public Flux<Menu> getAllMenus() {
    Flux<Menu> allMenuFlux = Flux.empty();
    Flux<Foodtruck> foodtruckFlux = foodtruckService.getAllFoodtrucks();

    foodtruckFlux.toStream().forEach(foodtruck -> {
      Flux<Menu> currentMenuFlux = Flux.fromIterable(foodtruck.getMenus());
      allMenuFlux.mergeWith(currentMenuFlux);
    });

    return allMenuFlux;
  }
}

mergeWith似乎没有向 allMenuFlux 添加任何内容。我想我在这里有一个理解问题。

我已经阅读了文档,测试了其他方法,如concat或zip,但它并没有像我希望的那样交错磁通事件。我无法正确合并这些 Flux 。 我还认为有一种更好的方法可以通过菜单存储库获取mongo嵌入式文档,因为我的方法似乎有点矫枉过正,从长远来看可能会导致性能问题。我试过了,但是没有用。

编辑: 尝试以下代码后(确保我的列表不为空),生成的 fluxtest3 变量正确合并:

Flux<Menu> allMenuFlux = Flux.empty();
Flux<Foodtruck> foodtruckFlux = foodtruckService.getAllFoodtrucks();

List<Foodtruck> test = foodtruckFlux.collectList().block();

Flux<Menu> fluxtest1 = Flux.fromIterable(test.get(0).getMenus());
Flux<Menu> fluxtest2 = Flux.fromIterable(test.get(1).getMenus());
Flux<Menu> fluxtest3 = fluxtest1.mergeWith(fluxtest2);

但这不是我想要的。为什么不使用空助焊剂作为母通量。

我在这里缺少什么?

提前感谢您的帮助。

1 个答案:

答案 0 :(得分:2)

我认为这里有一些误解。

  1. 如果您将Flux转换为CollectionStream或类似内容,然后将某些内容转换回Flux,那么您肯定在做有问题。这些类强制您的管道收集多个元素,然后处理它们,然后将它们转换回Flux。几乎在所有情况下,只有Flux提供的操作才能实现这一点。

  2. Flux上的方法不会更改Flux,但会创建具有其他行为的新实例。所以如果你有这样的代码:

    Flux<Menu> allMenuFlux = Flux.empty();
    Flux<Foodtruck> foodtruckFlux = foodtruckService.getAllFoodtrucks();
    
    foodtruckFlux.toStream().forEach(foodtruck -> {
        Flux<Menu> currentMenuFlux = Flux.fromIterable(foodtruck.getMenus());
        allMenuFlux.mergeWith(currentMenuFlux);
    });
    

    返回allMenuFlux;

    每次调用allMenuFlux.mergeWith(currentMenuFlux);时,都会创建一个新的Flux,以便垃圾收集器可以处理它。 allMenuFlux仍然是你开始的那个空的“Flux。”

  3. 您真正想要的是:

    return foodtruckService.getAllFoodtrucks()
        .flatMap(Foodtruck::getMenus);
    

    请参阅flatMap的文档。 flatMapmergeWith之间的区别在于mergeWith保留了原始元素。如果您的用例中没有,则多余是多余的。

  4. 奖金:您的其他问题

    Flux<Menu> fluxtest1 = Flux.fromIterable(test.get(0).getMenus());
    Flux<Menu> fluxtest2 = Flux.fromIterable(test.get(1).getMenus());
    Flux<Menu> fluxtest3 = fluxtest1.mergeWith(fluxtest2);
    

    此处您不会返回原始fluxtest1,而是返回新生成的fluxtest2。因此它确实有效。