英文:
How to retrieve Users' comment with their profile image and name?
问题
目前,我正在制作一个社交媒体应用,项目中使用了 Firebase Firestore 和云存储。应用中有一个评论按钮,如果用户点击该按钮,他应该能够看到每个用户的评论,以及评论者的姓名和个人头像。
这是我的 Firestore 数据库结构:
Users(根集合)
|---- UID1([文档]由认证生成的用户ID)---[字段-姓名、头像、年龄]
|---- UID2([文档]由认证生成的用户ID)---[字段-姓名、头像、年龄]
Posts(根集合)
|-----DOCID1(字段-帖子标题、发布者UID、帖子图片)
|----Comments(子集合)
|----1RANDOMDOCID(字段-评论者用户ID、评论日期、评论内容)
|----2RANDOMDOCID(字段-评论者用户ID、评论日期、评论内容)
好的,我需要将这些评论填充到一个回收视图(RecycleView)中。我将在下面添加我的方法:
Query query = db.collection("Posts").document(CURRENT_SELECTED_DOC_ID).collection("Comments");
PagedList.Config config = new PagedList.Config.Builder()
.setEnablePlaceholders(false)
.setInitialLoadSizeHint(10)
.setPageSize(20)
.build();
FirestorePagingOptions<CommentsI> options = new FirestorePagingOptions.Builder<CommentsI>()
.setQuery(query, config, CommentsI.class)
.build();
构造函数
public class CommentI {
String Commented_User_Id;
Date Commented_Date;
String Comment;
public CommentI(){
//空构造函数
}
public CommentI(String commented_User_Id, Date commented_Date, String comment){
Commented_User_Id = commented_User_Id;
Commented_Date = commented_Date;
Comment = comment;
}
public String getCommented_User_Id(){
return Commented_User_Id;
}
public Date getCommented_Date(){
return Commented_Date;
}
public String getComment(){
return Comment;
}
}
这是在回收视图中填充项的常规方法。我可以毫无疑问地获取这些评论和日期,但是我同时需要设置用户的头像和姓名。这就是我必须在解决这个问题之前停下来的地方。请有人帮助我解决这个问题:)
编辑
以下是我的适配器。当我们尝试像下面这样检索用户信息时,在上下滚动时它总是读取 Firestore 文档。例如,当我从第一个项目滚动到第十个项目,然后从第十个项目滚动到第一个项目时,我会看到姓名和头像在每次滚动时刷新。如何解决这个问题?
@Override
protected void onBindViewHolder(@NonNull final CommentIViewHolder holder, int position, @NonNull CommentI model) {
holder.comment_textview.setText(model.getComment());
holder.date_textview.setText(DateFormat.format("(yyyy-MM-dd)", model.getCommented_Date()));
// 获取用户ID
String UserId = model.getCommented_User_Id();
final FirebaseFirestore db = FirebaseFirestore.getInstance();
DocumentReference documentReference = rootRef.collection("Users").document(UserId);
documentReference.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
@Override
public void onComplete(@NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()){
DocumentSnapshot doc = task.getResult();
if (doc.exists()) {
String UserName = doc.getString("Name");
String UserImage = doc.getString("Image");
holder.commentor_name.setText(UserName);
holder.setProfile_image_view(UserImage);
}
}
}
});
}
英文:
Currently, I am make a social media app and I am using firebase firestore and cloud storage for my project. There is a comment button and if the user clicks the button he should be able to see every users' comments with their name and profile image.
This is my firestore database structure,
Users(Root collection)
|---- UID1([Document]User ID which generate by authentication)---[Fields-Name,Image,Age]
|---- UID2([Document]User ID which generate by authentication)---[Fields-Name,Image,Age]
Posts(Root collection)
|-----DOCID1(Fields-Post Title,Posted_UID,Post_Image)
|----Comments(Sub-collection)
|----1RANDOMDOCID(Fields-Commented_User_Id,Commented_Date,Comment)
|----2RANDOMDOCID(Fields-Commented_User_Id,Commented_Date,Comment)
Alright, I need to populate these comments to a recycleview. I ll add my approach below,
Query query = db.collection("Posts").document(CURRENT_SELECTED_DOC_ID).collection("Comments");
PagedList.Config config = new PagedList.Config.Builder()
.setEnablePlaceholders(false)
.setInitialLoadSizeHint(10)
.setPageSize(20)
.build();
FirestorePagingOptions<CommentsI> options = new FirestorePagingOptions.Builder<CommentsI>()
.setQuery(query, config, CommentsI.class)
.build();
Constructor
public class CommentI {
String Commented_User_Id;
Date Commented_Date;
String Comment;
public CommentI(){
//Empty constructor
}
public class CommentI(String commented_User_Id,Date commented_Date,String comment){
Commented_User_Id = commented_User_Id;
Commented_Date = commented_Date;
Comment = comment;
//------------------------------------------
public String getCommented_User_Id(){
return Commented_User_Id;
}
public Date getCommented_Date(){
return Commented_Date;
}
public String getComment(){
return Comment;
}
This is the usual way to populate items in recycleview. I can get these comments and date without any doubt, But I need to set the users' Image and name same time. this is the point where I had to stop my work until solve this. Please someone help
Edit
Here is my adapter and when we trying retrieve user info like this, it always reads the firestore document while scrolling up and down. For example - When I scrolling up and down(Just think i got 10 items in recyleview), I can see name and image refreshing everytime when scrolling from item 1 to 10 and from item 10 to 1. How to fix this?
@Override
protected void onBindViewHolder(@NonNull final CommentIViewHolder holder, int position, @NonNull CommentI model) {
holder.comment_textview.setText(model.getComment());
holder.date_textview.setText(DateFormat.format("(yyyy-MM-dd)", model.getCommented_Date()));
//getting UserID-------------
String UserId = model.getCommented_User_Id();
final FirebaseFirestore db = FirebaseFirestore.getInstance();
DocumentReference documentReference = rootRef.collection("Users").document(UserId);
documentReference.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
@Override
public void onComplete(@NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()){
DocumentSnapshot doc = task.getResult();
if (doc.exists()) {
String UserName = doc.getString("Name");
String UserImage = doc.getString("Image");
holder.commentor_name.setText(UserName);
holder.setProfile_image_view(UserImage);
}
}
}
});
答案1
得分: 0
TL;DR - 将图像和名称数据添加到您的“Comments”文档中(同时仍然保留在“Users”文档中)
根据上面的信息,我看到两种可能的方法:
- 循环遍历评论,收集评论者的UID,然后获取该UID的“Users”文档,并在其中显示图像。
- 在首次创建“Comments”文档时,将有关发表评论的用户的所有相关信息复制到“Comments”文档中。
在这两种方法中,我强烈推荐使用方法#2。
在为NoSQL设计数据模型时(实际上就是确定要放入文档中的数据),考虑一下您的应用程序以及您想要在特定屏幕上显示什么。尽量将尽可能多的数据放入一个给定屏幕的单个文档中,以避免读取其他文档。
这种方法可能会让从SQL背景转过来的人感到有些不适。在SQL领域,我们都接受通过“数据规范化”来消除数据重复的训练。其中很多都源于SQL起源于存储空间“昂贵”的世界。
在NoSQL领域,比如Firestore,基本的假设是:
- 存储是便宜的
- 写入(创建/更新/删除)不频繁且“昂贵”
- 检索的是原子“文档” >> 推论:没有“连接”
在NoSQL领域,我们真的不介意数据重复。我们希避免获取一个文档(评论)后还需要进行其他文档的获取(用户)。
英文:
TL;DR - add the Image & Name data to your Comments document (and still keep it in the Users document)
From the info above, I see two possible approaches:
- Loop over the comments gathering the commenter's UID and then get the Users document for that UID and display the image within
- When you create the Comments document in the first place, copy all relevant information about the User making the comment into the Comments document
Of the 2 approaches, I would strongly encourage #2.
When designing the data model for NoSQL (essentially - when determining what data to put into a document), think about your app and what you want to display on a given screen. Try to put as much data in a single document for that given screen as possible to avoid reading additional documents.
This approach will feel "icky" to people coming from a SQL background. In SQL land, we are all trained to eliminate data duplication via "data normalization". Much of this stems from the origins of SQL in a world where storage space was "expensive".
In NoSQL land - such as Firestore - the base assumptions are
- storage is cheap
- writes (create/update/delete) are infrequent and "expensive"
- you fetch "documents" that are atomic >> corollary: there are no "joins"
In NoSQL land, we really don't mind data duplication. We want to avoid fetching one document (Comment) and be required to do additional document fetches (Users).
答案2
得分: 0
好的,以下是翻译好的部分:
抱歉,我的错误。我建议您使用 Firebase 用户 对象来存储 图像 URL,但您只能获取当前用户的图像(这不是您想要的)。
所以需要将其存储在数据库中。现在,正如 @Greg 所说,您有两种方法,我也建议您使用第二种方法,但如果您的用例需要使用第一种方法,那么这是您要做的:
1. 在评论文档中存储用户的 UID(您已经完成了这一步)。
2. 获取特定帖子的评论(您也已经完成了这一步)。
现在,在这之后,您在 onBindViewHolder
中获取用户文档,这是强烈不建议的,因为您的 recyclerView
中 onBindViewHolder
会被多次调用,这会导致性能问题和成本上升。
根据您的代码,我猜测您正在使用 FirebaseUI(我没有使用过),但我认为您应该自己像这样执行此方法(我最近遇到过类似情况,并且是这样做的):
3. 获取特定帖子的评论并将其存储在类似 ArrayList
的结构中。
4. 遍历评论,获取每个用户的文档并将它们也存储在 ArrayList
中。
5. 在适配器的构造函数中传递这两个 ArrayList
,然后在 onBindViewHolder
中设置它们。
现在,当我做类似的事情时,我遇到了一种异常行为,您可以在这里看到(如果您正在遵循此答案),在我的问题中(由我自己提供的答案):在 Android 中循环运行 Firebase get()
尽管如此,这会消耗大量资源!
英文:
Okay, my bad. I suggested you to use the Firebase User object to store the image URL but you can only get the image of the current user (which is not what you want).
So storing in the database is needed. Now, as @Greg said that you have two approaches and I would also recommend having the second but if your use case is such that you need to have the first approach then here's what you do:
1. Store the user's UID in the comments documents (which you have already done).
2. Get the comments of the particular post (which too, you have already done).
Now, after this, you are getting the user's document in onBindViewHolder
which is strongly discouraged as because your onBindViewHolder
would be called many times in your recyclerView
which would have performance issues and cost uprising.
By seeing your code, I am assuming that you are using FirebaseUI (with which I have no experience) but I think you should do this approach on your own like this (I recently had such case and did like this):
3. Get the comments of the particular post and store it in something like an ArrayList
.
4. Loop over the comments, get each user's documents and store them also in Arraylist
.
5. Pass both the ArrayLists
in your constructor of the adapter and then just set them up in onBindViewHolder
.
Now, when I was doing something similar like this, I got an unusual behaviour which you should see here (if you are following this answer) in my question (with the answer given by myself): Running Firebase get() in a loop in android
Although, this would cost you a lot!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论