使用angularfire2查询数据库上的数据关系

时间:2021-04-08 16:54:49

I need to query comments and request only user that listed in the comment by userId.

我需要查询注释并只请求userId列出的用户。

My database structure in Firebase realtime db:

我在Firebase realtime db中的数据库结构:

{
  "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",
    }
  }
}

What I need in the end is Comment[], where Comment is:

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

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

so, the class for Comment is

评论类是

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

So far I managed to get ALL users and then map them to comments on the client side. But wouldn't it be to much in case when db will have N number of users and only 2 comments, where N>>2?

到目前为止,我设法获得了所有用户,然后将它们映射到客户端上的注释。但是,如果db有N个用户,只有2个评论,而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;
      });
  }

Is there a way get only users from comments?

是否有方法只能从评论中获取用户?

I also tried to add this to the User, but did not manage it to work:

我也尝试把这个添加到用户中,但是没有成功:

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

Update 0

更新0

I have edited the question, I hope now is more clear.

我已经编辑了这个问题,我希望现在能更清楚一些。

I have been able to make it work like this: solution from - https://www.firebase.com/docs/web/guide/structuring-data.html and https://firebase.google.com/docs/database/web/read-and-write

我已经能够让它像这样工作:解决方案:https://www.firebase.com/docs/web/guide/structuring-data.html和https://firebase.google.com/docs/database/web/readand -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() ));
      });
    });
  }

but I want to convert this to Observable, because with this I can not see if the comment have been deleted without refreshing the page.

但是我想把它转换成可观察的,因为如果不刷新页面,我无法看到注释是否被删除。


Update 1

更新1

With the help from comment bellow I came out with this implementation.

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

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

This returns separate comments, where I would rather receive Comment[], I'll try to use child events: "child_added", "child_changed", "child_removed", and "child_moved" with snapshotChanges() instead .valueChanges().

这返回了单独的注释,我宁愿收到注释[],我将尝试使用子事件:“child_add”、“child_changed”、“child_remove”和“child_moved”,并使用snapshotChanges() (). valuechanges()。

1 个解决方案

#1


1  

Ok so according to your updates, I would personally first create a couple helper interfaces:

好的,根据你的更新,我个人首先会创建两个助手界面:

interface User {
    userId: string;
    userName: string;
}

interface FullComment {
    commentId: string;
    userId: string;
    user: User;
}

interface CommentObject {
    commentId: string;
    commentText: string;
    userId: string;
}

And then super handy helper methods:

然后是非常方便的助手方法

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

So finally look how easy it becomes to get the FullComment objects observable:

所以,最后看一下,获得完整的评论对象是多么容易的事情:

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

I think this is what you need. Please let me know if this is helpful. Happy coding with observables ;)

我想这就是你需要的。如果有用的话,请告诉我。愉快的可观察编码)

Latest update: Previously forgot to make a last transformation to fix the TypeError, so now it must be ok.

最新更新:先前忘记做最后一个转换来修复类型错误,所以现在它必须是ok的。

#1


1  

Ok so according to your updates, I would personally first create a couple helper interfaces:

好的,根据你的更新,我个人首先会创建两个助手界面:

interface User {
    userId: string;
    userName: string;
}

interface FullComment {
    commentId: string;
    userId: string;
    user: User;
}

interface CommentObject {
    commentId: string;
    commentText: string;
    userId: string;
}

And then super handy helper methods:

然后是非常方便的助手方法

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

So finally look how easy it becomes to get the FullComment objects observable:

所以,最后看一下,获得完整的评论对象是多么容易的事情:

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

I think this is what you need. Please let me know if this is helpful. Happy coding with observables ;)

我想这就是你需要的。如果有用的话,请告诉我。愉快的可观察编码)

Latest update: Previously forgot to make a last transformation to fix the TypeError, so now it must be ok.

最新更新:先前忘记做最后一个转换来修复类型错误,所以现在它必须是ok的。