【问题标题】:RXJS filter on another observableRXJS 过滤另一个 observable
【发布时间】:2017-03-11 04:04:44
【问题描述】:

在我的代码中,我从MS Graph 获取用户列表,但这列出了所有用户。我只想发出属于指定组的那些用户。所以我设置了一个过滤器:

private loadUsers() {
    console.log(`Loading users...`);
    this.graph.get$(`users`)
        .map(resp => resp.json().value)
        .flatMap(user => user)
        .do(user => {
            console.log(`Got user: ${user['displayName']}`);
        })
        .filter(user => {
            // we only want users who are members of the TrackerContact group
            const userId: string = user['id'];
            console.log(`Checking user ${userId}`);
            return this.userIsTrackerContact(user); // <<= PROBLEM HERE!
        })
        .subscribe(_ => {
            console.log(`Completed user fetch!`);
        });
}

问题是为了找出用户属于哪些组,我必须再次调用 REST 回 MS Graph

private userIsTrackerContact(user): Observable<boolean> {
    // get the groups this user is a member of
    return this.graph.get$(`users/${user['id']}/memberOf`)
        .map(resp => resp.json().value)
        .do(groups => {
            console.log(`${user['displayName']} is a member of ${groups.length} groups:`);
            groups.forEach((group, idx) => {
                console.log(`   [${idx+1}]: ${group['displayName']}`);
            })
        })
        .map(groups => {
            const found = groups.find((group) => group['id'] === this.authConfig.azureGroups.trackerContact)
            return !isUndefined(found);
        })
}

在我看来,filter 一个 Observable 基于另一个 observable 是不可能的。谓词测试必须是简单的真/假测试。

如何根据另一个 Observable 的结果过滤一个 Observable?

【问题讨论】:

  • 您需要在服务端对其进行过滤以获得轻量级数据。两者同时执行还是?
  • 我必须同意@Aravind。向服务器询问已过滤的用户集合,然后获取更大的用户集合,然后为每个用户发出 http 请求以过滤它们,这样效率更高。
  • @stely000:虽然我原则上同意,而且我实际上使用完全不同的技术解决了这个问题,但我想问题仍然存在。如果没有其他办法怎么办?

标签: javascript typescript rxjs observable


【解决方案1】:

.concatAll() 可能会更好:

this.graph.get$(`users`)
    .map(resp => resp.json().value)
    .flatMap(user => user)
    .do(user => {
        console.log(`Got user: ${user['displayName']}`);
    })
    .filter(user => {
        // we only want users who are members of the TrackerContact group
        const userId: string = user['id'];
        console.log(`Checking user ${userId}`);
        return this.userIsTrackerContact(user); // <<= PROBLEM HERE!
    })
    .concatAll()
    .subscribe(...)

我相信你应该能够merge async observables 然后过滤。

Rx.Observable.merge(this.graph.get$(`users`)
    .map(resp => resp.json().value)
    .flatMap(user => user)
    .do(user => {
        console.log(`Got user: ${user['displayName']}`);
    })
    .map(user => {
        // we only want users who are members of the TrackerContact group
        const userId: string = user['id'];
        console.log(`Checking user ${userId}`);
        return this.userIsTrackerContact(user); // <<= PROBLEM HERE!
    }))
    .filter(x => x)
    .subscribe(_ => console.info('success'));

您可以更改您的谓词设置用户 isGroupMember 的属性。然后filter(x =&gt; x.isGroupMember)。然后在 subscribe 方法中有用户对象。

【讨论】:

  • 我最终选择了一个完全不同的方向,并实施了一个我更满意的解决方案。我最终做的是触发 3 个 Observables,将它们全部转换为 Promises,然后对所有三个对象执行 .all([...])。这三个承诺返回了我需要的所有数据。但是我仍然会接受这个答案,因为在没有其他选择的情况下它似乎是正确的。
猜你喜欢
  • 2019-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-03
  • 1970-01-01
  • 2017-11-19
  • 1970-01-01
相关资源
最近更新 更多