简体   繁体   English

在RxJS中使用过滤运算符

[英]Using Filter Operator in RxJS

Update: I altered the votes node of the database. 更新:我更改了数据库的投票节点。 It didn't seem to make sense the way I had it structured. 我构建它的方式似乎没有意义。

This is my database structure: 这是我的数据库结构:

-threadsMeta
    -posts
        -postId


-votes
    -threadId
        -postId
            -uid: "down" //or "up"

The comments in the below code, I think, describe the intended behavior versus the actual behavior. 我认为以下代码中的注释描述了预期的行为与实际的行为。

getMyUpVotes(threadId: string, uid: string): Observable<any> {
    //Get all the postId's for this thread
    let myUpVotes = this.af.database.list(`threadsMeta/${threadId}/posts`)
    .map(posts => {
        //Put each postId into a Firebase query path along with the uid from the method's params
        posts.forEach(post => {
            this.af.database.object(`votes/${threadId}/${post.$key}/upVotes/${uid}`)
            //Emit only upvotes from this user on this post
            .filter(data => data.$value === true)
        })
    })
    myUpVotes.subscribe(data => console.log(data)) //Undefined
    return myUpVotes
}

The following method would return the array of posts with an upvote + for the given thread + for the given user: 以下方法将为给定用户返回给定线程+的带有upvote +的帖子数组:

getMyUpVotes(threadId: string, uid: string): Observable<any> {
  return this.af.database.list(`threadsMeta/${threadId}/posts`).take(1)
    // Flatten the posts array to emit each post individually.
    .mergeMap(val => val)
    // Fetch the upvotes for the current user on the current post.
    .mergeMap(post =>
      this.af.database.object(`votes/${threadId}/${post.$key}/upVotes/${uid}`).take(1)
        // Only keep actual upvotes
        .filter(upvote => upvote.$value === true)
        // Convert the upvote to a post, since this is the final value to emit.
        .map(upvote => post)
    )
    // Gather all posts in a single array.
    .toArray();
}

I've added the .take(1) to force Firebase observables to complete so that the final results can be collected with toArray() . 我添加了.take(1)来强制完成Firebase可观察对象,以便可以使用toArray()收集最终结果。 That also means that once you have fetched the upvotes, you stop watching for future value changes. 这也意味着,一旦您获取了票数,就不再关注未来的价值变化。 Let me know if this is a problem. 让我知道是否有问题。

IMPORTANT. 重要。 You should subscribe to the observable from OUTSIDE of your method. 您应该从方法的外部订阅可观察的内容。

I have created a runnable version to illustrate (note that I'm using plain observables as neither Angular nor Firebase are available in this environment): 我创建了一个可运行的版本来进行说明(请注意,由于在此环境中Angular和Firebase都不可用,所以我使用的是普通的可观察对象):

 const getPostsForThread = (threadId) => { return Rx.Observable.of([ { key: 'jcormtp', title: 'Some post', threadId: threadId }, { key: 'qapod', title: 'Another post', threadId: threadId }, { key: 'bvxspo', title: 'Yet another post', threadId: threadId } ]); } const getUpvotesPerPostPerUser = (postId, uid) => { return Rx.Observable.from([ { postId: 'jcormtp', uid: 'bar', value: true }, { postId: 'qapod', uid: 'bar', value: false }, { postId: 'bvxspo', uid: 'bar', value: true } ]).filter(uv => uv.postId == postId && uv.uid == uid); } const getMyUpVotes = (threadId: string, uid: string): Rx.Observable<any> => { return getPostsForThread(threadId) // Flatten the posts array to emit each post individually. .mergeMap(val => val) // Fetch the upvotes for the current user on the current post. .mergeMap(post => getUpvotesPerPostPerUser(post.key, uid) // Only keep actual upvotes .filter(upvote => upvote.value === true) // Convert the upvote to a post, since this is the final value to emit .map(upvote => post) ) // Gather all posts in a single array .toArray(); } // NB. subscribe() outside of the method getMyUpVotes('foo', 'bar') .subscribe(val => console.log(val)); 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.0.1/Rx.min.js"></script> 

I think you want: 我想你要:

let myUpVotes = this.af.database.list(`threadsMeta/${threadId}/posts`)
    .flatMap(posts => 
          Observable.from(posts)
              .flatMap(post=>this.af.database.object(
                   `votes/${threadId}/${post.$key}/upVotes/${uid}`));
myUpVotes = myUpVotes.flatMap(t=>t.filter(x=>x.uid === true));

So I did come up with a solution that suited my particular situation well. 因此,我确实提出了一个非常适合我的特定情况的解决方案。 I just don't know enough about observables to know whether it might be the best way to do this. 我只是对可观察对象还不了解,因此不知道这可能是最好的方法。 Anyway, I ended up 'joining' the query with my posts query. 无论如何,我最终以帖子查询“加入”了查询。 This works well for my particular situation because I'm rendering the posts with ngFor . 这对我的特定情况很好,因为我使用ngFor渲染帖子。 I'm able to check whether the current user has upvoted/downvoted the specific post with this: 我可以通过以下方法检查当前用户是否对特定帖子进行了投票:

<i [class.voted]="post.vote === 'down'" class="fa fa-caret-down" aria-hidden="true"></i>

Here's how I'm getting the data: 这是我获取数据的方式:

getPosts(threadId: string, uid: string): Observable<any> {
    let result = this.af.database.list(`/threads/${threadId}/posts`)
    .switchMap(posts => {
        let joinedObservables: any[] = [];
        posts.forEach(post => {
            joinedObservables.push(this.af.database
                .object(`votes/${threadId}/${post.$key}/${uid}`)
                .do(value => {
                    post.vote = value.$value
                })
            )
        })
        return Observable.combineLatest(joinedObservables, () => posts);

    });
    return result
}

In this implementation I keep getting the emissions from the votes, which is important, as user votes have to be reflected on the page not just on load but if they change their votes. 在此实现中,我不断从票证中获取排放量,这很重要,因为用户票证不仅要反映在页面上,还必须反映他们的票数,如果他们改变了。

I'd like to know whether anyone foresees any issues with this. 我想知道是否有人预见到任何问题。 I'm not at all good with this technology, and I wonder if I'm missing anything. 我对这项技术一点都不满意,我想知道我是否缺少任何东西。 I'll give the others who have answered the opportunity to voice any objections and to edit their own answers if they want before choosing this as the answer. 在选择答案之前,我将给其他回答过的人提出异议和编辑自己的答案的机会。

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

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