2017-05-08 55 views
0

我需要结合两个Obersvables。Observable in Observables

products 
---1 
    ---name: 'product 1' 
    ---supplierId: '1' 
---2 
    ---name: 'product 2' 
    ---supplierId: '2' 

suppliers 
---1 
    ---name: 'supplier 1', 
    ---contact: 'contact 1',  
---2 
    ---name: 'supplier 2', 
    ---contact: 'contact2' 

最后我想获得以下信息:

[ 
    { 
    name: 'product 1' 
    supplierId: '1', 
    supplier: { name: 'supplier 1', contact: 'contact1'} 
    }, 
    { 
    name: 'product ´2' 
    supplierId: '2', 
    supplier: { name: 'supplier 2', contact: 'contact2'} 
    }, 
] 

此刻,我有以下代码:

this.af.list('products') 
    .map(products => { 
    let items = []; 
    (<Array<any>>products).forEach(p => { 
     if (p.supplierId) { 
     let supplier$ = this.af.object(`suppliers/${p.supplierId}`).take(1); 

     items.push(Observable.forkJoin(Observable.of(p), supplier$, (p1, supplier) => { 
      return { 
      name: p1.name, 
      supplier: supplier 
      }; 
     })) 
     } 
    }) 
    return items; 
    }) 
    .do(res => console.log('After Map', res)) 
    .flatMap(res => Observable.combineLatest(Observable.of(res))) 
    .subscribe(res => console.log('Final Response', res)) 

不要紧,我尝试,我要么接受没有任何东西或一个ForkJoinObservables数组。

回答

2

有没有必要使用flatMapcombineLatest

我已经做了一个小Plunkr来演示如何做到这一点。

首先,我不希望把那个无关的问题太多的代码,我已经建立了我的例子不折角,以及使用嘲笑:

模拟数据来自未来后端:

// raw objects that simulate the backend 
const products = [ 
    { 
    name: 'product 1', 
    supplierId: '1' 
    }, 
    { 
    name: 'product 2', 
    supplierId: '2' 
    } 

]; 

const suppliers = [ 
    { 
    name: 'supplier 1', 
    contact: 'contact 1' 
    }, 
    { 
    name: 'supplier 2', 
    contact: 'contact2' 
    } 
]; 

模拟来模拟你的角度服务(它返回一个可观察):

// simulate the angular service with HTTP 
// use Observable.of and not Observable.from because we get the product list in one reponse 
const getProducts =() => { 
    return Observable.of(products).delay(1000); 
}; 

const getSupplierByName = (name) => { 
    const supplier = suppliers.find(s => s.name === `supplier ${name}`); 

    return Observable.of(supplier).delay(1000); 
}; 

最后,如预期的代码检索数据:

// now let's try to get your data as you want, which is : 
// get the whole product list 
// for each product, get his supplier 
// merge the data into one big result 
getProducts() 
    .switchMap(products => 
    Observable 
     .forkJoin(products 
     .map(product => getSupplierByName(product.supplierId) 
      .map(supplier => (Object.assign({}, product, { supplier }))))) 
) 
    .do(console.log) 
    .subscribe(); 

下面是我们在控制台中看到的结果:

enter image description here

+0

谢谢,最后它在你的榜样工作:) – Benny

0

使用扫描操作。将产品,供应商和结果保存在累加器中,并在可能时加入。当你能够创建一个结果对象可能还需要清理的产品和供应商名单(我没有做到这一点)

扫描:

应用在源可观察累加器函数并返回每个中间结果,带有可选的种子值。

http://reactivex.io/rxjs/class/es6/Observable.js~Observable.html#instance-method-scan

let o1$ = Rx.Observable.of({ 
     name: 'product 1', 
     supplierId: '1' 
    }, 
    { 
     name: 'product 2', 
     supplierId: '2' 
    }); 

    let o2$ = Rx.Observable.of({ 
     name: 'supplier 1', 
     contact: 'contact 1' 
    }, 
    { 
     name: 'supplier 2', 
     contact: 'contact 2' 
    }); 

    Rx.Observable.merge(o1$, o2$) 
    .scan((acc, el) => { 
     // product 
     if (el.supplierId) { 
      // check in supplier queue 
      let supplier = 
      acc.suppliers.find(supplier => supplier.name === ('supplier ' + el.supplierId)); 
      if (supplier) { 
      acc.results.push({ 
       name: el.name, 
       supplierId: el.supplierId, 
       supplier: {name: supplier.name, contact: supplier.contact} 
      }); 
      } 
      else { 
      acc.products.push(el); 
      } 
     } 
     // supplier 
     else { 
      // check in product queue 
      let product = 
      acc.products.find(product => ('supplier ' + product.supplierId) === el.name); 
      if (product) { 
      acc.results.push({ 
       name: product.name, 
       supplierId: product.supplierId, 
       supplier: {name: el.name, contact: el.contact} 
      }); 
      } 
      else { 
      acc.suppliers.push(el); 
      } 
     } 
     return acc; 
     }, 
     {suppliers: [], products: [], results: []} 
    ) 
    .subscribe(({results}) => console.log(results)); 
+0

没有必要来表示'01 $'随着时间可观察到的返回多个值。如果你看看Benny的代码:'this.af.list('products').map(products => ...)'。他在一个电话中获得了整个名单。但是在那之后,他每个产品**打一个电话**以确保供应商 – Maxime

+0

确实可见,但是随着时间的推移可观察到可以发出多个值,并且扫描将累积这些值。当一个观察值只生成一个值时,一次调用获取产品是有限的情况。 –