在RxJS中使用过滤器运算符

时间:2017-02-25 00:06:12

标签: angular typescript firebase-realtime-database rxjs angularfire2

更新:我更改了数据库的投票节点。我的结构似乎没有意义。

这是我的数据库结构:

-threadsMeta
    -posts
        -postId


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

我认为以下代码中的注释描述了预期的行为与实际行为。

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
}

3 个答案:

答案 0 :(得分:1)

以下方法将为给定用户返回给定线程+的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();
}

我添加了.take(1)以强制完成Firebase可观察项,以便可以使用toArray()收集最终结果。这也意味着一旦你获得了赞成票,你就会停止观察未来的价值变化。如果这是一个问题,请告诉我。

重要。您应该从方法的OUTSIDE订阅observable。

我创建了一个可运行的版本来说明(请注意,我使用的是普通的observable,因为在这种环境下,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>

答案 1 :(得分:0)

我想你想要:

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

答案 2 :(得分:0)

所以我确实想出了一个适合我特殊情况的解决方案。我只是不太了解observables知道它是否是最好的方法。无论如何,我最终用我的帖子查询'加入'查询。这适用于我的特定情况,因为我使用ngFor呈现帖子。我能够检查当前用户是否已对此特定帖子进行了投票/投票:

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

以下是我获取数据的方式:

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
}

在这个实现中,我不断从投票中获得排放,这很重要,因为用户投票必须反映在页面上,不仅仅是在加载,而且如果他们改变了投票。

我想知道是否有人预见到这方面的任何问题。我对这项技术并不擅长,我想知道我是否遗漏了任何东西。我会给那些已经回答机会发表任何反对意见的人,并在选择这个答案之前编辑他们自己想要的答案。