【问题标题】:Query data relationship on Firebase Realtime Database with angularfire2使用 angularfire2 查询 Firebase 实时数据库上的数据关系
【发布时间】:2018-06-22 09:33:26
【问题描述】:

我需要查询 cmets 并仅请求 userId 在评论中列出的用户。

我在 Firebase 实时数据库中的数据库结构:

{
  "comments" : {
    "c_id1" : {
      "commentId" : "c_id1",
      "commentText" : "text",
      "userId" : "u_id1"
    },
    "c_id2" : {
      "commentId" : "c_id2",
      "commentText" : "text",
      "userId" : "u_id3"
    },
  },

  "users" : {
    "u_id1" : {
      "userId" : "u_id1",
      "userName" : "name1",
    },
    "u_id1" : {
      "userId" : "u_id2",
      "userName" : "name2",
    },
    "u_id1" : {
      "userId" : "u_id3",
      "userName" : "name3",
    }
  }
}

我最后需要的是Comment[],其中Comment是:

{
  "commentId" : "c_id",
  "commentText" :"text",
  "userId" : "u_id",
  "user" : {
    "userId":"u_id",
    "userName":"name"
  }
}

所以,Comment 的类是

export class Comment {
  commentId: string;
  commentText: string;
  userId: string;
  user?: User;
}

到目前为止,我设法获得了所有用户,然后将它们映射到客户端的 cmets。但是如果 db 有 N 个用户并且只有 2 个 cmets,其中 N>>2,这不是很多吗?

  OnGetUsersForComments(){
    return this.angularFireDatabase.list("/comments").valueChanges()
      .subscribe((data) => {
        this.commentsUsers = data;
        this.OnGetCommentsForTask()
      });
  }

  OnGetCommentsForTask(){
    this.angularFireDatabase.list("/comments").valueChanges()
      .map((comments) => {
        return comments.map( (comment: TaskComment) => {
          this.commentsUsers.forEach((user: User) => {
            if (comment.userId === user.userId) {
              comment.commentUser = user;
            }
          });
          return comment;
        });
      })
      .subscribe((data)=> {
        this.comments = data;
      });
  }

有没有办法只从 cmets 获取用户?

我也尝试将此添加到用户,但没有管理它工作:

"userComments" : {
  "uc_id1" : {
    "commentId" : c_id2
  },
}

更新0

我已经编辑了问题,希望现在更清楚。

我已经能够使它像这样工作: 来自-https://www.firebase.com/docs/web/guide/structuring-data.html的解决方案 和 https://firebase.google.com/docs/database/web/read-and-write

 comments: TaskComment[] = [];

 onGetComments(){
    var ref = firebase.database().ref('/');

    ref.child('comments/').on('child_added', (snapshot)=>{
      let userId = snapshot.val().userId;
      ref.child('users/' + userId).on('value', (user)=>{
        this.comments.push( new TaskComment( snapshot.val(), user.val() ));
      });
    });
  }

但我想将其转换为 Observable,因为这样我无法在不刷新页面的情况下查看评论是否已被删除。


更新 1

在下面评论的帮助下,我提出了这个实现。

onGetComments(){
  this.angularFireDatabase.list("/comments").valueChanges()
    .mergeMap((comments) => {
      return comments.map((comment)=>{
        this.firebaseService
          .onListData('/users', ref => ref.orderByChild('userId').equalTo(comment.userId))
          .valueChanges()
          .subscribe((user: User[])=> {
            comment.user = user[0];
          })
        return comment;
      })
    })
    .subscribe((comment)=> {
      console.log(comment);
    });
}

这将返回单独的 cmets,我宁愿在其中接收 Comment[],我将尝试使用子事件:“child_added”、“child_changed”、“child_removed”和“child_moved”与 snapshotChanges() 而不是 .valueChanges( )。

【问题讨论】:

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


    【解决方案1】:

    好的,根据你的更新,我个人会先创建几个帮助接口:

    interface User {
        userId: string;
        userName: string;
    }
    
    interface FullComment {
        commentId: string;
        userId: string;
        user: User;
    }
    
    interface CommentObject {
        commentId: string;
        commentText: string;
        userId: string;
    }
    

    然后是超级方便的辅助方法:

    getUser(uid: string): Observable<User> {
        return this.db.object<User>(`/users/${uid}`)
        .valueChanges()
    }
    
    getFullComment(commentObject: CommentObject): Observable<FullComment> {
        return this.getUser(commentObject.userId)
        .map((user: User) => {
            return {
                commentId: commentObject.commentId,
                commentText: commentObject.commentText,
                user: user,
            };
        });
    }
    

    所以最后看看让 FullComment 对象可观察变得多么容易:

    getComments(): Observable<FullComment[]> {
        return this.db
        .list(`/comments`)
        .valueChanges()
        .switchMap((commentObjects: CommentObject[]) => {
            // The combineLatest will convert it into one Observable
            // that emits an array like: [ [fullComment1], [fullComment2] ]
            return Observable.combineLatest(commentObjects.map(this.getFullComment));
        });
    }
    

    我认为这就是您所需要的。请让我知道这是否有帮助。 使用 observables 进行愉快的编码 ;)

    最新更新:之前忘记做最后一次转换修复TypeError,现在应该没问题了。

    【讨论】:

    • 嗨。感谢您的回复,我给了我一些新的信息供我搜索和研究。
    • 但这并不是我想要的。我已经更新了这个问题,希望现在更清楚。我尝试使用 .switchMap 和 .mergeMap 来实现我需要的东西,但是在订阅时我得到了单独的“评论”对象,所以当它是新添加或删除时它会变得疯狂。希望我能尽快处理。
    • 你是天才。谢谢。但我不太确定 .map(Array.prototype.concat) 的用途,因为在我的情况下,它只是添加了 MapSubscriber {closed: false, ... } 对象和最后的空 0 元素。所以在 4 cmets 的情况下,我得到了 6 个元素的数组。
    • 那么它现在在您的应用中是否按您预期的方式工作?
    • 好的,我刚刚意识到没有必要连接最终的数组。我的错对不起
    猜你喜欢
    • 2017-10-13
    • 1970-01-01
    • 1970-01-01
    • 2022-01-05
    • 2019-07-31
    • 1970-01-01
    • 2018-02-19
    • 2023-03-17
    • 2018-04-07
    相关资源
    最近更新 更多