简体   繁体   English

将多个可观察数组合并到新对象数组中

[英]Combine multiple observable arrays into new object array

I have 3 observable arrays like below. 我有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"}]

I am trying to combine these 3 into below result , 我试图将这3个结合到下面的结果中,

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

To get the desired result, I have used map function on persons observable to give new object array. 为了得到理想的结果,我在可观察的人身上使用了map函数来给出新的对象数组。

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

PersonDetail object has firstName , lastName , location and department properties. PersonDetail对象具有firstNamelastNamelocationdepartment属性。 How do I do a lookup into departments observable and get a matching row for departmentID to get the department name ? 如何做一个查找到的部门观察到,并得到一个匹配的行为departmentID获得部门的名字吗?

I am new to rxjs library, please let me know if there is a better way to attain the desired result. 我是rxjs库的新手,请告诉我是否有更好的方法来达到预期的效果。

Since you'll very likely want to fetch lists of departments and locations from a remote service (make another HTTP request) I'd do it right away with Observables as well. 由于您很可能想要从远程服务获取部门和位置列表(发出另一个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));

This prints to console: 这打印到控制台:

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

There're two Observables department$ and location$ that are filtered with filter() operator to get the only item with matching ID. 有两个Observables department$location$使用filter()运算符进行过滤,以获得唯一具有匹配ID的项目。 Then forkJoin() operator waits until both of them are complete. 然后forkJoin()运算符等待,直到它们都完成。 Operator mergeMap() then reemits the value returned from forkJoin() . 运算符mergeMap()然后重新发送从forkJoin()返回的值。 At the end with toArray() we collect all items into a single array. 最后使用toArray()我们将所有项目收集到一个数组中。

Instead of Observable.from(...) you can have whatever service you'll need (eg. http.get(...) ). 而不是Observable.from(...)你可以得到你需要的任何服务(例如http.get(...) )。

See live demo: https://jsbin.com/nenekup/4/edit?js,console 查看现场演示: https//jsbin.com/nenekup/4/edit?js,console

Similar questions: Merge subarrays using Observables and Subscribing to a nested Observable 类似问题: 使用Observables订阅嵌套Observable来 合并子阵列

It's not clear what exactly your observables are emitting, so I considered two options. 目前尚不清楚你的观察者究竟发出了什么,所以我考虑了两种选择。

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);
});

i think the RxJS .zip operator may be your friend here. 我认为RxJS .zip运营商可能是你的朋友。

As far as I understand, .zip emits like this ... 据我所知,.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 
})

Something like that! 这样的东西! Hopefully, puts you on the right track. 希望,让你走上正轨。

.zip should emit the first time when all 3 have emitted (and it will emit a second time when all three stream have emitted twice, etc) - In your scenario I expect all three stream emit once only, which makes it a simple case for .zip .zip应该在所有3个已经发出时第一次发出(当所有三个流都发出两次时它会发出第二次,等等) - 在你的场景中我希望所有三个流只发出一次,这使得它很简单。压缩

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM