角度-将多个可观察对象链接在一起

问题描述

我有三个返回观测值的服务。第一个返回配方列表,第二个返回给定配方的所有配料,最后一个返回给定配料类型的数量。我想调用所有三个连续传递先前信息到下一个调用方法,以便将返回的响应映射到相同的配方初始列表。本质上,每个连续的调用都会添加到先前返回的信息中,并且每个连续的调用都会增加对象列表的复杂性。我还需要对每个返回值应用自定义映射。我还需要他们同时解决问题,因此我可以简单地订阅最终结果。我知道我可能需要使用switchMap或concatMap,但是我不确定如何构造它。

任何帮助将不胜感激

我的服务呼叫及其映射示例

获取食谱

let allRecipes: Observable<RecipeModel[]> = this.recipeListService.GetRecipesFromAirtable(
      allTypes,allOccassions,allPrepStyles,allFamilies,muddlingReq,allPrimaryComponents,allSecondaryComponents,recipeName
    ).pipe(map(response => {
      let allRecipes: RecipeModel[] = response.records.map(
        recipeObj => {
          //console.log(recipeObj.fields);

          let model: RecipeModel = {
            id: recipeObj.fields["Recipe ID"],name: recipeObj.fields["Name"],variant: '',version: 0,type: recipeObj.fields["Type"]
          }

          let variant: string = recipeObj.fields["Variant"];
          if(variant !== null && variant !== undefined) {
            model.variant = variant;
          }

          let version: number = recipeObj.fields["Version"];
          if(version !== null && version !== undefined && isNaN(version) !== true) {
            model.version = version;
          }

          return model;
        }
      )

      return allRecipes;
    }));

获取成分

let allIngredients: Observable<IngredientModel[]> = this.ingredientService.GetIngredientsFromAirtable(recipe.id)
    .pipe(
      map(response => {
      let allIngredientObjs: IngredientModel[] = response.records.map(
        ingredientObj => {
          let model: IngredientModel = {
            order: ingredientObj.fields["Order"],name: ingredientObj.fields["Ingredient Name"][0],qualifier: ingredientObj.fields["Qualifier"],optional: ingredientObj.fields["Optional"] ? ingredientObj.fields["Optional"] : false,amountReq: { },notes: ingredientObj.fields["Notes"]
          }

          let allFields: [string,string][] = [["Cups","cup"],["Ounces","oz"],["Millilitres","mL"],["Quantity",""],["Grams","g"],["Dashes",["Barspoons","barspoons"],["Teaspoons","tsp"],["Misc",""]];
          for(let i = 0; i < allFields.length; i++) {   
            let fieldName: string = allFields[i][0];
            let value: string = ingredientObj.fields[fieldName];

            if(value === null || value === undefined || value.length == 0) {
              continue;
            }

            model.amountReq[fieldName.toLowerCase()] = {units: allFields[i][1],amount: value};
          }

          // Add type info
          model.type = {
            superType: ingredientObj.fields["Ingredient Supertype"],type: ingredientObj.fields["Ingredient Type"],subType: ingredientObj.fields["Ingredient Subtype"]
          }

          return model;
        }
      )

      return allIngredientObjs;
    }));

获取配料数量

let ingredientQuantity: Observable<number> = this.inventoryService.GetIngredientQuantitiesFromAirtable(
      inventoryName,ingredientName)
    .pipe(
      map(response => {
        let quantity = 0;

        let allLiquorObjs = response.records.map(
          liquorObj => {
            let model = {
              brand: liquorObj.fields["Brand"][0],desc: liquorObj.fields["Description"][0],volume: liquorObj.fields["Current Volume (mL)"]
            }

            if("specialValue" in model.volume) {
              model.volume = -1;
            }

            if(model.volume > 0) {
              quantity += model.volume;
            }

            // return model;
          }
        )

        return quantity;
      }));

到目前为止,在Elias Dal Ben的帮助下,我已经完成了以下工作

let allRecipes: Observable<RecipeModel[]> = this.getAllRecipesObservable(this.allDrinkTypes,this.allDrinkOccassions,this.allPreparationStyles,this.allFamilies,this.muddlingrequired,this.allPrimaryComponents,this.allSecondaryComponents,this.recipeNametoFind)
    .pipe(
      tap(allRecipes => { 
        console.debug('Recipes(' + allRecipes + ')'); 
      }),concatMap(data => {
        let allRecipes = data;
        allRecipes.map(
          recipe => {
            let allIngredients: Observable<IngredientModel[]> = this.getAllIngredientsObservable(recipe);

            allIngredients.pipe(
              tap(allIngredients => {
                console.debug('Ingredients(' + allIngredients + ')');
              }),concatMap(data => {
                let allIngredients = data;
                allIngredients.map(
                  ingredient => {
                    let quantity: Observable<number> = 
                    this.getIngredientQuantityObservable(this.inventoryAddr,ingredient.type.name);
                    
                    quantity.pipe(
                      tap(quantity => {
                        console.debug('Quantity(' + quantity + ')');
                      })
                    )

                    return quantity;
                  }
                )
              })
            )

            return allIngredients;
          }
        )

        return allRecipes;
      })
    )

但是在第一行,allRecipes给我一个错误

“类型'Observable'不能分配给类型'Observable '”

第二个concatMap中的数据给我一个错误

“类型'(data:IngredientModel [])=> void'的参数不能分配给类型'('value:IngredientModel [],index:number)=> ObservableInput'的参数。 类型'void'不能分配给类型'ObservableInput'。”

有人知道我想念什么吗?

解决方法

它非常冗长,但是您可以使用rx/operators concatMap函数

let result = allRecipes.pipe(
  concatMap(recipes => allIngredients.pipe(
     concatMap(ingredients => ingredientQuantity.pipe(
        map(quantity => [ ...ingredients,...recipes,quantity ])
     ))
  ))
)

然后,您只需订阅此结果即可使用[ ...ingredients,quantity ]结构或任何结构