问题
I have a RecyclerView which is populated by posts stored in a Firestore database. Each post is written as a document with a unique postID, storing the posted message, a timestamp and a like-counter.
//mUploads is defined as private List<Upload> mUploads;
//Upload object stores post message, timestamp and likes
mUploads = new ArrayList<>();
mFireStoreOrdered = mFireStoreInst.collection("posts").orderBy("time");
mFireStoreOrdered
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (DocumentSnapshot doc : task.getResult()) {
//For each document get the ID
String postID = doc.getId();
// Upload object stores post message, timestamp and likes
Upload upload = doc.toObject(Upload.class).withId(postID);
mUploads.add(upload);
}
Collections.reverse(mUploads);
//Populate Recyclerview
mAdapter = new UploadAdapter(MainActivity.this, mUploads);
mContentView.setAdapter(mAdapter);
} else {
//...
}
}
});
When trying to implement the "like"-functionality for these posts I got to the limits of Firestore, which can only handle one document update per second.
Reading this article convinced me of using the Firebase Realtime Database to store the likes by using transaction operations instead of using distributed counters. I do not want to display the likes in real-time, I only want to use the RTDB to handle multiple likes/dislikes per second.
When additionally using the Firebase RTDB for likes, I would add data to a path /posts/postID/likes.
How can I get the post messages from Firestore and add the corresponding likes from the RTDB to mUploads
before passing it to the adapter. Specificially, is it possible to ensure that I set the correct like value to its corresponding post, without querying for each postID.
回答1:
This is a very common practice when it comes to Firestore, to store the number of likes in the Firebase Realtime database, otherwise you'll be charged for every read/write operation as explained in my answer from this post. So using Firebase Realtime database you can host the number of likes at no cost.
So, how can be done? First of all, you are guessing right. The number of likes should be added beneath the postId
like this:
Firebase-root
|
--- likes
|
--- postIdOne: numberOfLikes //must be stored as an integer
|
--- postIdOTwo: numberOfLikes //must be stored as an integer
|
--- //and so on
To achive what you want, you need to follow the next steps.
- Every time you you add a new post, add the corresponding post id in Firebase Realtime database like above by setting the value of that particular post id to
0
. - Every time you get a new like increase the value of that postId by one. Every time a user retracts a like, decrease the value of that postId by one. To achieve this and also to have consistent data, I recommend you use Firebase Transactions.
Then in your adapter class, where you are displaying data from Firestore, when you want to set the number of likes to a view, just attach a listener on that particular post id node and get the number of likes. Inside the
onDataChange()
set that number to aTextView
like this:DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference(); DatabaseReference noOfLikesRef = rootRef.child("likes").child(postId); ValueEventListener valueEventListener = new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { String numberOfLikes = "(" + dataSnapshot.getValue() + ")"; numberOfLikesTextView.setText(numberOfLikes); } @Override public void onCancelled(DatabaseError databaseError) {} }; noOfLikesRef.addListenerForSingleValueEvent(valueEventListener);
That's it!
来源:https://stackoverflow.com/questions/49561360/using-data-from-firestore-and-firebase-rtdb-in-single-recyclerview