I want to show all the documents that are in a collection using ListView in my app. For this, I need to retrieve all the documents, right? How can I do this? I've searched a lot but couldn't find anything in Google Docs / any proper solution.
Be careful, as each document returned counts as a 'read'. Make sure you've read the pricing section of firestore. If you had 10,000 documents in this collection, every time you made this query you'd be using 10,000 reads.
Nevertheless, the query is:
FirebaseFirestore.getInstance()
.collection("collectionname")
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
List<DocumentSnapshot> myListOfDocuments = task.getResult().getDocuments();
}
}
});
Related
I have some Firestore requests that I try to get in a for loop, but because Firebase queries are running Async, the results return in random order. Do you have any way to fix it? My code is below.
Thank you in advance!
for(Feed feed: feedList){
tasks.add(db.document(feed.getMarker().getPath()).get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
myMarker.add(task.getResult().toObject(SavedMarker.class));
System.out.println("Marker: "+ Objects.requireNonNull(task.getResult().toObject(SavedMarker.class)).getDescription());
System.out.println("Marker: "+task.getResult().getId());
}
}));
tasks.add(db.document(feed.getUser().getPath()).get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
myUser.add(task.getResult().toObject(Users.class));
}
}));
}
Tasks.whenAllSuccess(tasks).addOnCompleteListener(new OnCompleteListener<List<Object>>() {
#Override
public void onComplete(#NonNull Task<List<Object>> task) {
//Do Stuff
}
For Example:
IDX Gives ResultX
In my feedList I have saved 4 ids like:
ID1
ID2
ID3
ID4
But when i try to receive their results with the use of a loop i get:
Result2
Result1
Result3
Result4
The order is usually random.
because Firebase queries are running Async, the results return in random order.
The whenAllSuccess() method from the Tasks class will always provide the documents from the tasks right into the callback in a List<Object>. The order is the same as the order in which the tasks were added to the whenAllSuccess() method. However, if you need an order other than that, then you should either order them on the client in the way you want or create a query based on a field and order the documents as needed.
How should I fetch the document fields from one collection and combine them to add a new document to another collection? I have attached picture of the database how does it looks, I want to fetch the fields from the collection show and want to update it to the new collection along with some other data:
private void savePost(String mPostTitle, String mPostContent, String mlistSpinnerC) {
final DocumentReference docRef = FirebaseFirestore.getInstance().collection("users").document(mauth.getCurrentUser().getUid());
docRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document != null) {
String username = (String)
document.get("username");
String email= (String) document.get(email);
} else {
Log.d(TAG, "No such document");
}
} else {
Log.d(TAG, "get failed with ", task.getException());
}
}
});
postMap.put(Constants.POSTTTITLE, mPostTitle);
postMap.put(Constants.POSTCATEGORY, mlistSpinnerC);
postMap.put(Constants.POSTCONTENT, mPostContent);
postMap.put(Constants.TIMESTAMP, (System.currentTimeMillis()/1000));
postMap.put(Constants.USER_ID,mauth.getCurrentUser().getUid());
postMap.put("username", username);
PostsRef.document().set(postMap).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if(task.isSuccessful()){
Intent toHomeActivity = new Intent(AddPostActivity.this, MainActivity.class);
startActivity(toHomeActivity);
}
}
});
I am just not able to map the fields from one collection to another collection, please guide me the correct method to that.
By the time you are trying to add the username to your postMap using the following line of code:
postMap.put("username", username);
The data has not finished loading yet from the database and this is because the listener you have added to your get() call is being invoked some unknown amount of time later after your query finishes. You don't know how long it's going to take, it may take from a few hundred milliseconds to a few seconds before that data is available. The onComplete() method has an asynchronous behavior, that's why you cannot get that username in such a way.
A quick solve for this problem would be to move all that block of code related to adding data to the postMap, inside the onComplete() method. In this you are waiting for the callback and username your will be available. Otherwise I recommend you see the last part of my anwser from this post in which I have explained how it can be done using a custom callback. You can also take a look at this video for a better understanding.
I'm using Firebase Realtime Database and I need to do multiple operations in the database, some of that depending on the result of the previous, creating the famous 'callback hell'. How can i handle errors when, for example, the second call goes wrong, but the first one succeeded ?
I tried to find some "Firebase realtime database transaction" (like transactions in mysql or postgres), but didn't find any good examples.
mDb.getReference("users").setValue("someValue").addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if(task.isSuccessful()){
mDb.getReference("services").setValue("someValue2").addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if(task.isSuccessful()){
mDb.getReference("stores").setValue("someValue3").addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
// Here, for some reason, the value "someValue3" could not be set.
}
});
}
}
});
}
}
});
I need that, if some operation goes wrong, to revert ('rollback') the values set before. Right now, if the transaction on reference 'stores' fail, the values set on 'users' and 'services' will keep on the database.
If you want to update multiple values in the database in one call, use a multi-location update that André mentioned in his comment.
With a multi-location update, your entire code can be reduced to:
Map<String, Object> values = new HashMap<>();
values.put("users", "someValue");
values.put("services", "someValue2");
values.put("stores", "someValue3");
mDb.updateChildren(values).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
// All writes either completed, or none happened
}
});
Some notes:
The keys in the values map can contain entire paths, so if you want to update the name of a specific user it could be values.put("users/uidOfTheUser/name", "new name").
If you need to write a new value based on the existing value of a node, you will need to use transactions instead. But note that transactions across multiple top-level nodes tend to be highly contentious, so I'd recommend trying to stay away from them in your current use-case.
On Firestore I am trying to add a document to one collection based on the existance of another document from a different collection. For example, if a certain session exists in my session collection, then an attendance record can be added to the attendance collection. Is this possible to achieve on Cloud Firestore?
You can use the function 'exists' within your security rules to validate the a specific document exists on a different collection. Check this document for reference: https://firebase.google.com/docs/firestore/security/rules-conditions#access_other_documents
You can solve this on user side by calling exists() method on a DocumentSnapshot object to check if a particular document exists or not in your session collection like this:
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
DocumentReference docRef = rootRef.collection("session").document(docId);
docRef.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
//Add attendance record to the attendance collection
} else {
Log.d(TAG, "No such document");
}
}
}
});
To be 100% procent sure you can also use security rules as also #Gerardo mentioned in his answer, where you can use again exists() method to see if a certain session exists or not in your session collection and reject the action accordingly.
I have created a application using Firestore in this app I want to save a same string in all documents of a collection in one click
For Example: See in the image. I have created a collection name Links. In this Collection I have created many Documents.
So I want to save string field: name and value:anyname, in all documents in one click on press button.
How it's possible? Please help.
To achieve this, please use the following code:
CollectionReference linksRef = rootRef.collection("Links");
linksRef.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : task.getResult()) {
Map<String, Object> map = new HashMap<>();
map.put("propertyName", "propertyValue");
placesRef.document(document.getId()).update(map);
}
}
}
});
All your documents will have now a new propertyName property that will hold the value of propertyValue.