英文:
How to display a document with its subcollections from Firestore in a RecyclerView with Android?
问题
这是我的Firestore数据库的样子:
(图片描述)
我有一个RecyclerView,用于显示帖子列表。但是我无法检索带有其子集合的文档并将其放入对象中。当我在我的RecyclerView
中提交帖子列表时,我希望每个帖子已经有其赞和评论。
我使用AsyncTask来执行查询用户所有帖子的后台工作。异步任务完成后,它将帖子列表提交给RecyclerView(仍然不起作用)。
在下面的代码中,我正在调用用户的所有帖子,然后获取每个帖子的“赞”。
我在每个帖子内部放置了一个while循环,以便在继续处理下一个帖子快照之前,可以等待它完成查询赞。
doInBackground()
final List<Post> postList = new ArrayList<>();
// -- 获取用户的所有帖子
feedsCollection.document(documentID).collection("Posts").get()
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
for(final DocumentSnapshot documentSnapshot1 : queryDocumentSnapshots){
final Post post = documentSnapshot1.toObject(Post.class);
// 在继续之前先完成获取赞和评论
while(post.isStillLoading()){
// -- 获取每个帖子的赞
db.collection("FeedsCollection").document(documentID).collection("Posts")
.document(documentSnapshot1.getId()).collection("Likes").get()
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
List<Like> likeList = new ArrayList<>();
for(DocumentSnapshot likeSnapshot : queryDocumentSnapshots){
Like like = likeSnapshot.toObject(Like.class);
likeList.add(like);
}
post.setLikes(likeList);
post.setStillLoading(false);
}
});
// -- 获取评论代码
}
postList.add(post);
}
}
});
return postList;
onPostExecute()
protected void onPostExecute(List<Post> postList) {
super.onPostExecute(postList);
adapter.submitData(postList);
}
这些是我尝试过的方法:
- 我尝试在我的RecyclerView中有多个视图类型,这样如果列表为空,它会显示“无项目”。然后当AsyncTask完成时,它会重新向RecyclerView提交列表。
- 我尝试使用FirestoreRecyclerAdapter,但我读到它的查询是浅层查询,所以不能一次性获取每个帖子文档的赞和评论子集合。
还有其他解决方法吗?
英文:
This is what my Firestore database looks like:
I have a RecyclerView which displays a list of posts. But I am not able to retrieve a document with its subcollections and put it inside an object. When I submit a list of posts in my RecyclerView
, I want each post to already have its Likes and Comments.
I use AsyncTask to do the background work of querying all the posts of the user. After the AsyncTask is done, it will submit the List of posts to the RecyclerView. (Still doesn't work)
In the code below, I'm calling all the Posts of the user and then getting the "Likes" of each post.
I have put a while loop inside each post so that I can wait for it to finish querying the Likes before proceeding to the next Post snapshot
doInBackground()
final List<Post> postList = new ArrayList<>();
// -- GET all the posts of the user
feedsCollection.document(documentID).collection("Posts").get()
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
for(final DocumentSnapshot documentSnapshot1 : queryDocumentSnapshots){
final Post post = documentSnapshot1.toObject(Post.class);
// Finish getting the likes&comments before proceeding
while(post.isStillLoading()){
// -- GET Likes of each post
db.collection("FeedsCollection").document(documentID).collection("Posts")
.document(documentSnapshot1.getId()).collection("Likes").get()
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
@Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
List<Like> likeList = new ArrayList<>();
for(DocumentSnapshot likeSnapshot : queryDocumentSnapshots){
Like like = likeSnapshot.toObject(Like.class);
likeList.add(like);
}
post.setLikes(likeList);
post.setStillLoading(false);
}
});
// -- GET comments code
}
postList.add(post);
}
}
});
return postList;
onPostExecute()
protected void onPostExecute(List<Post> postList) {
super.onPostExecute(postList);
adapter.submitData(postList);
}
These are the things I've tried:
- I tried having multiple
viewtypes in my recyclerview, so that if the list is still empty, it
displays "No items". And then when the AsyncTask finish, it will
re-submit a list to the recyclerview. - I tried to use FirestoreRecyclerAdapter but I've read that its queries are shallow so it can't get the Likes and Comments subcollections of each post document altogether.
Any other workaround for this?
答案1
得分: 4
-
"But I am not able to retrieve a document with its subcollections and put it inside an object."
- "但是我无法检索一个文档及其子集合并将其放入一个对象中。"
-
"There's no way you can achieve this. The queries in Firestore are shallow, so it is allowed to only get documents from the collection that the query is run against. Furthermore, there is no way you can get a document together with the nested subcollections in a single go. You can get the document and then run separate queries for each and every subcollection."
- "你无法实现这一点。Firestore中的查询是浅层的,因此只能获取与查询所针对的集合中的文档。此外,无法一次性获取文档及其嵌套的子集合。您可以获取文档,然后为每个子集合运行单独的查询。"
-
"Another possible solution might be to use Firebase Realtime Database, where when you download a node, you download it together with all the data that exist beneath that node."
- "另一个可能的解决方案是使用Firebase实时数据库,在那里,当您下载一个节点时,您将同时下载该节点下存在的所有数据。"
-
"I use AsyncTask to do the background work of querying all the posts of the user."
- "我使用AsyncTask来执行查询用户所有帖子的后台工作。"
-
"The Cloud Firestore client already runs all network operations in a background thread. This means that all operations take place without blocking your main thread. Putting it in an
AsyncTask
does not give any additional benefits."- "Cloud Firestore客户端已经在后台线程中运行所有网络操作。这意味着所有操作都在不阻塞主线程的情况下进行。将其放入AsyncTask中不会提供任何额外的好处。"
英文:
> But I am not able to retrieve a document with its subcollections and put it inside an object.
There's no way you can achieve this. The queries in Firestore are shallow, so it is allowed to only get documents from the collection that the query is run against. Furthermore, there is no way you can get a document together with the nested subcollections in a single go. You can get the document and then run separate queries for each and every subcollection.
Another possible solution might be to use Firebase Realtime Database, where when you download a node, you download it together with all the data that exist beneath that node.
> I use AsyncTask to do the background work of querying all the posts of the user.
The Cloud Firestore client already runs all network operations in a background thread. This means that all operations take place without blocking your main thread. Putting it in an AsyncTask
does not give any additional benefits.
答案2
得分: 0
如果您在多个集合中(甚至是嵌套的集合)拥有数据,您将需要执行多个查询来获取所有这些数据。仅通过单个查询是不可能实现的。您当然可以实现您想要的功能,但这将会显著增加复杂性。
需要执行一个查询来获取 PostsCollection 中的所有文档,然后需要更多的查询来获取每个帖子的 Comments 和 Likes 下的嵌套子集合中的数据。
正如 Alex 所建议的,切换到实时数据库可能不是一个好主意。您将失去许多复杂的查询能力,仅为了进行深层查询,而且您可能并不总是希望始终进行完全深入的查询,因为这可能会在整体上增加更多的费用。
英文:
If you have data in multiple collections, even nested collections, you will have to perform multiple queries to get all that data. It won't be possible with just a single query. You can certainly implement what you want, it will just be significantly more complex to do so.
It will require one query to get all the documents in PostsCollection, then more queries for each of the subcollections nested under Comments and Likes for each of the posts.
Switching to Realtime Database as Alex suggests might not be a good idea. You will lose a lot of more complex querying capability just to get deep queries, and you might not even want fully deep queries all the time, as that could be more expensive overall.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论