【问题标题】:Combine multiple observable arrays into new object array将多个可观察数组组合成新的对象数组
【发布时间】:2017-05-06 11:02:50
【问题描述】:

我有 3 个如下所示的可观察数组。

persons = [
   {
      "firstName":"john",
      "lastName":"public",
      "locationID":"1",
      "departmentID":"100"
   },
   {
      "firstName":"sam",
      "lastName":"smith",
      "locationID":"2",
      "departmentID":"101"
   }
]

departments = [{"departmentID": "100",
               "name": "development"
               },
               {"departmentID": "101",
                "name": "sales"
               }]

locations = [{"locationID": "1", "name": "chicago"},
              {"locationID":"2", "name": "ny"}]

我正在尝试将这 3 个组合到以下结果中,

result = [
   {
      "firstName":"john",
      "lastName":"public",
      "location":"development",
      "department":"sales"
   },
   {
      "firstName":"sam",
      "lastName":"smith",
      "location":"ny",
      "department":"sales"
   }
]

为了得到想要的结果,我对可观察的人使用了 map 函数来提供新的对象数组。

this.store<Person>('persons')
.map(function(person){
     let p = new personDetail()
     p.firstName = person.firstName,
     p.lastName = person.lastName
     return p;
})

PersonDetail 对象具有firstNamelastNamelocationdepartment 属性。如何查找部门 observable 并获取 departmentID 的匹配行以获取部门名称?

我是 rxjs 库的新手,如果有更好的方法来获得所需的结果,请告诉我。

【问题讨论】:

    标签: javascript angular typescript rxjs rxjs5


    【解决方案1】:

    不清楚你的 observables 到底发出了什么,所以我考虑了两个选项。

    let persons = [
        {
            "firstName":"john",
            "lastName":"public",
            "locationID":"1",
            "departmentID":"100"
        },
        {
            "firstName":"sam",
            "lastName":"smith",
            "locationID":"2",
            "departmentID":"101"
        }
    ];
    
    let departments = [
        {"departmentID": "100", "name": "development"},
        {"departmentID": "101", "name": "sales"}
    ];
    
    let locations = [
        {"locationID": "1", "name": "chicago"},
        {"locationID": "2", "name": "ny"}
    ];
    
    // Option 1: first observable emits persons one by one, 
    // locations and departments are emitted as whole arrays.
    let o1: any = Observable.from(persons);
    let o2: any = Observable.of(departments);
    let o3: any = Observable.of(locations);
    
    o1.withLatestFrom(o2, o3, (p, d, l) => {
        // here it is probably better to convert array to some kind of map or dictionary,
        // but I'm only showing Rxjs concept of doing such things.
        let location = l.find(c => c.locationID === p.locationID);
        let department = d.find(c => c.departmentID === p.departmentID);
        return {
            firstName: p.firstName,
            lastName: p.lastName,
            location: location ? location.name : "",
            department: department ? department.name : ""
        };
    }).subscribe((f) => {
        console.log(f);
    });
    
    // Option 2: all observables emit elements one by one.
    // In this case we need to convert departments and locations to arrays.
    o1 = Observable.from(persons);
    o2 = Observable.from(departments);
    o3 = Observable.from(locations);
    
    o1.withLatestFrom(o2.toArray(), o3.toArray(), (p, d, l) => {
        // this part of code is exactly the same as in previous case.
        let location = l.find(c => c.locationID === p.locationID);
        let department = d.find(c => c.departmentID === p.departmentID);
        return {
            firstName: p.firstName,
            lastName: p.lastName,
            location: location ? location.name : "",
            department: department ? department.name : ""
        };
    }).subscribe((f) => {
        console.log(f);
    });
    

    【讨论】:

      【解决方案2】:

      我认为 RxJS .zip 运算符可能是你的朋友。

      据我了解,.zip 发出这样的...

      .zip(
         Observable.from[array1].switchMap( // map to http response here ),
         Observable.from[array2].switchMap( // map to http response here ),
         Observable.from[array3].switchMap( // map to http response here )
      ).map((valueFromArray1, valueFromArray2, valueFromArray3) {
         // Create your object here 
      })
      

      类似的东西!希望能让您走上正轨。

      .zip 应该在所有 3 个都发出时第一次发出(当所有三个流都发出两次时,它会第二次发出,等等) - 在你的场景中,我希望所有三个流只发出一次,这使它成为.zip 的简单案例

      【讨论】:

      • 有趣,我不知道 zip 功能。按照马丁的建议,我能够使用 forkJoin 让它工作。
      【解决方案3】:

      因为您很可能希望从远程服务获取部门和位置列表(发出另一个 HTTP 请求),所以我也会立即使用 Observables 来完成。

      Observable.from(persons)
          .mergeMap(person => {
              let department$ = Observable.from(departments)
                  .filter(department => department.departmentID == person.departmentID);
      
              let location$ = Observable.from(locations)
                  .filter(location => location.locationID == person.locationID);
      
              return Observable.forkJoin(department$, location$, (department, location) => {
                  return {
                      'firstName': person.firstName,
                      'lastName': person.lastName,
                      'location': location.name,
                      'department': department.name,
                  };
              });
          })
          .toArray()
          .subscribe(result => console.log(result));
      

      这会打印到控制台:

      [ { firstName: 'john',
          lastName: 'public',
          location: 'chicago',
          department: 'development' },
        { firstName: 'sam',
          lastName: 'smith',
          location: 'ny',
          department: 'sales' } ]
      

      有两个 Observable department$location$ 使用 filter() 运算符过滤以获得唯一具有匹配 ID 的项目。然后forkJoin() 操作员等待它们都完成。运算符mergeMap() 然后重新发送从forkJoin() 返回的值。以toArray() 结尾,我们将所有项目收集到一个数组中。

      除了Observable.from(...),您可以使用任何您需要的服务(例如http.get(...))。

      观看现场演示:https://jsbin.com/nenekup/4/edit?js,console

      类似问题:Merge subarrays using ObservablesSubscribing to a nested Observable

      【讨论】:

      • 谢谢,我能够使用 forkJoin 让它工作。
      • 您能否详细解释一下为什么需要 mergeMap 或它的作用?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多