Database Snapshot Image
Here is a piece of code I am using to get things from a collection into my own class object. I've now tried a bunch of things [using DocumentReference, looking up different code available online etc.] but the problem still persists.
I cannot retrieve data which I know is stored in the Firestore. When I execute the code, I get that the QueryDocSnap is empty.
CollectionReference reference = firestore.collection("data");
reference.get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
if (queryDocumentSnapshots.isEmpty()) {
Log.i(TAG, "QueryDocSnap is empty");
} else {
List<ReportStore> types = queryDocumentSnapshots.toObjects(ReportStore.class);
reportStores.addAll(types);
Global.setStoreData(reportStores);
}
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.e(TAG, "Error Getting Data", e);
}
});
/app/store/data/4EOi3Eh1AkZf1rK5zwKt is the hierarchy of my database with Firestore telling me that 'app' and 'data' are Collection and the other two are Document.
Could someone please clear out this confusion of mine. Thank you.
This code will provide you proper list of documents from data.
CollectionReference reference = firestore.collection("app").document("store").collection("data");
reference.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : task.getResult()) {
Log.d(TAG, document.getId() + " => " + document.getData());
}
} else {
Log.d(TAG, "Error getting documents: ", task.getException());
}
}
});
Related
I want to push my data (in key:value pair) into my Realtime Database. This is my code:
DatabaseReference pay_details = database.getReference("pay/0/0/");
pay_details.push(
{
"Actual amount":arr.get(i).get(9),
"Current reading":arr.get(i).get(5),
"Employee":arr.get(i).get(1),
"Expected amount":arr.get(i).get(9),
"Installment":arr.get(i).get(10),
"Meter current date":arr.get(i).get(3),
"Meter previous date":arr.get(i).get(2),
"Previous reading":arr.get(i).get(4),
"Start from":arr.get(i).get(8),
"Total charge":arr.get(i).get(7),
"Type":arr.get(i).get(0),
"Unit consumed":arr.get(i).get(6)
}
);
This is my table structure:
I keep getting multiple syntax errors in the push section. Where am I going wrong?
The best way to send/store data in real-time database is to create an object of
Hashmap. Below is the code to achieve this objective
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference();
HashMap<String, Object> data = new HashMap<>();
data.put("Actual amount", Your actual amount);
data.put("Current reading", Your current reading);
data.put("Employee", Employee name);
databaseReference.child("The child name")
.updateChildren(data)
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void unused) {
Log.d("TAG", "Data added successfully");
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.d("TAG", "Failed " + e.getMessage());
}
});
The add data to the Realtime Database you need to use setValue() method. In code
DatabaseReference pay_details = database.getReference("pay/0/0/");
HashMap<String, Object> map = new HashMap<>();
map.put("fieldName", "fieldValue");
pay_details.setValue(map).addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
Log.d(TAG, "Data added successfully.");
} else {
Log.d(TAG, task.getException().getMessage()); //Never ignore potential errors!
}
}
});
If you want to add multiple children, then you can also use push().
I am working on an application where I have saved my data in firebase Firestore in nested collection now when I am trying to get/retrieve the data from Firestore but not able to get it. please guide me where am I wrong??
CODE TO WRITE/ADD THE DATA IN FIRESTORE
DocumentReference uidRef = firebaseFirestore.collection("listing_details").document(uid);
uidRef.collection("room_details").add(user).addOnSuccessListener(new OnSuccessListener<DocumentReference>() {
#Override
public void onSuccess(DocumentReference documentReference) {
Toast.makeText(getContext(), "data added", Toast.LENGTH_SHORT).show();
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(getContext(), "data adding failure", Toast.LENGTH_SHORT).show();
}
});
CODE FOR DATA RETRIEVING
db.collection("listing_details").document().collection("room_details").get().addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
List<DocumentSnapshot> list = queryDocumentSnapshots.getDocuments();
for (DocumentSnapshot d : list)
{
RoomsDetails obj = d.toObject(RoomsDetails.class);
roomsDetails.add(obj);
}
roomsAdapter.notifyDataSetChanged();
}
});
DATA RETRIEVING CODE (UPDATED)
roomDetailsRef.document(doc_id).get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
//GUIDE ME HERE HOW CAN I ITERATE THROUGH IT SIR PLEASE
}
});
Each time you're calling .document() to create the following reference, without passing anything as an argument:
db.collection("listing_details").document().collection("room_details")
// 👆
It means that you're generating a brand new unique document ID. If you want to create a reference that points to a particular document, then you have to pass the particular document ID that already exists in the database to the document() method, and not generate a new one.
So your code should look like this:
//Code to add data to Firestore.
FirebaseFirestore db = FirebaseFirestore.getInstance();
DocumentReference uidRef = db.collection("listing_details").document(uid);
CollectionReference roomDetailsRef = uidRef.collection("room_details");
String docId = roomDetailsRef.document().getId();
roomDetailsRef.document(docId).set(user).addOnSuccessListener(/*.../*);
// 👆
See, I have used DocumentReference#getId() to get the ID of the document, and DocumentReference#set(Object data) to actually add the document to Firestore.
//Code to read data from Firestore.
roomDetailsRef.document(docId).get().addOnSuccessListener(/*.../*);
// 👆
See, I have passed the document ID that was generated earlier, to the CollectionReference#document() method.
Edit:
If you want to get all documents that exist under the room_details collection, then please use the following lines of code:
roomDetailsRef.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : task.getResult()) {
if (document != null) {
RoomsDetails obj = document.toObject(RoomsDetails.class);
roomsDetails.add(obj);
}
}
roomsAdapter.notifyDataSetChanged();
} else {
Log.d(TAG, task.getException().getMessage()); //Never ignore potential errors!
}
}
});
In my app a first time user creates a username which I save in Firestore as a document and set it as displayName (username = name of document = displayName). In the app the user has the option to change his username by typing a new one in an EditText. The result should be that the data which is stored under his current username moves to a new document which has the new username. So first I check if the new username is already in use by someone else, if not I create a new document which name is the new username. Now I get the current displayName (which is the current username) as a string and the input of the EditText as a string (new username). I Implemented a method to move documents from here: How to move a document in Cloud Firestore?
But when I call the method like this moveFirestoreDocument(usernameInput, oldUsername ); I get:
moveFirestoreDocument cannot be applied to (String, String)
How can I resolve this problem? Can I change the moveFirestoreDocument method so it can also takes Strings?
Here is the method:
public void moveFirestoreDocument(DocumentReference fromPath, final DocumentReference toPath) {
fromPath.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document != null) {
toPath.set(document.getData())
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "DocumentSnapshot successfully written!");
fromPath.delete()
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "DocumentSnapshot successfully deleted!");
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.w(TAG, "Error deleting document", e);
}
});
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.w(TAG, "Error writing document", e);
}
});
} else {
Log.d(TAG, "No such document");
}
} else {
Log.d(TAG, "get failed with ", task.getException());
}
}
});
}
You get the following error:
I get "moveFirestoreDocument cannot be applied to (String, String)
Because you are trying to pass to the moveFirestoreDocument() method two arguments of type String and not of type DocumentReference. In order to be able to move a document, both fromPath and toPath must be of type DocumentReference so you can call set() on toPath and get() and delete() on fromPath.
Can I change the moveFirestoreDocument method so it can also takes Strings?
There is no need to change the method, you can simply pass the correct arguments when you call it. According to the details that you have provided in the question, I understand that you have a schema that is similar to this:
Firestore-root
|
--- users (collection)
|
--- John (document)
|
--- //User details
To rename the document call the method using:
FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
CollectionReference usersRef = rootRef.collection("users");
DocumentReference oldUsernameRef = usersRef.document(oldUsername);
DocumentReference usernameInputRef = usersRef.document(usernameInput);
moveFirestoreDocument(oldUsernameRef, usernameInputRef);
I'm trying to get a product from a document form the cloud firestore and then put that product in the shopping cart. When i read (successfully) the product, i try to put it in an arraylist that is declared outside but it doesnt work unless i put final to the variable.
Doing so, when I run the code below, I successfully retrieve the data, but the operation carrelloAttuale.prodotti.add(prod) is executed after the command transaction.update(), so the update doesn't upload nothing different from the start.
//prendo l'utente
FirebaseAuth auth= FirebaseAuth.getInstance();
//mi salvo il codice del prodotto scannerizzato
final String codiceProdottoScannerizzato=String.valueOf(intentData);
final FirebaseFirestore db = FirebaseFirestore.getInstance();
final DocumentReference docRef = db.collection("carrelli").document(auth.getUid());
final DocumentReference docrefprodotti = db.collection("prodotti").document(codiceProdottoScannerizzato);
db.runTransaction(new Transaction.Function<Void>() {
#Override
public Void apply(Transaction transaction) throws FirebaseFirestoreException {
DocumentSnapshot snapshot = transaction.get(docRef);
final Carrello carrelloAttuale = snapshot.toObject(Carrello.class);
docrefprodotti.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
Prodotti prod=document.toObject(Prodotti.class);
prod.id=codiceProdottoScannerizzato;
prod.totalePezziCarrello=1;
carrelloAttuale.prodotti.add(prod);
Log.d(TAG, "PRODOTTO: " + prod.toString());
} else {
Log.d(TAG, "No such document");
}
} else {
Log.d(TAG, "get failed with ", task.getException());
}
}
});
Log.d(TAG, "CARRELLO FB: " + carrelloAttuale.size());
transaction.update(docRef, "prodotti", carrelloAttuale.getProdotti());
// Success
return null;
}
}).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "Transaction success!");
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.w(TAG, "Transaction failure.", e);
}
});
I expect that the command update is executed after the carrelloAttuale.prodotti.add(prod)
in the debug log the order of tags are:
CARRELLO FB: 0
PRODOTTO: Nome: latte
Data is loaded from Firestore asynchronously, since it may have to be retrieved from the server. To prevent blocking the app, the main code continues while the data is being retrieved. Then when the data is available, your onComplete gets called.
This means that any code that needs the data from the data, must be inside the onComplete method, or be called from there. So something like:
docrefprodotti.get().addOnCompleteListener(new OnCompleteListener<DocumentSnapshot>() {
#Override
public void onComplete(#NonNull Task<DocumentSnapshot> task) {
if (task.isSuccessful()) {
DocumentSnapshot document = task.getResult();
if (document.exists()) {
Prodotti prod=document.toObject(Prodotti.class);
prod.id=codiceProdottoScannerizzato;
prod.totalePezziCarrello=1;
carrelloAttuale.prodotti.add(prod);
Log.d(TAG, "PRODOTTO: " + prod.toString());
} else {
Log.d(TAG, "No such document");
}
} else {
Log.d(TAG, "get failed with ", task.getException());
}
Log.d(TAG, "CARRELLO FB: " + carrelloAttuale.size());
transaction.update(docRef, "prodotti", carrelloAttuale.getProdotti());
}
});
Also see:
How to return a DocumentSnapShot as a result of a method?
Firebase Firestore get data from collection
"the command update" is executed before "carrelloAttuale.prodotti.add(prod)" is called because the onComplete() method has an asynchronous behaviour and returns immediately. This means that listener will not get invoked until some time later, after the database update operation is complete. There is no guarantee how long it will take. Depending on your connection speed and the state, it may take from a few hundred milliseconds to a few seconds for the update operation to complete.
If you want to use some logic with that data, you must wait until the asynchronous Firebase database operation is complete. This means that you can only use the prod object inside the listener callback itself.
For more informarions, 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.
Is this script wrong, because the data I receive is null while I've added data on the Cloud Firestore. I do not use RecyclerView because I only need one data only.
This is the script:
private void getCustomer(){
firestoreDB.collection("customer")
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
customers = new ArrayList<>();
for (DocumentSnapshot doc : task.getResult()) {
Customer customer = doc.toObject(Customer.class);
customer.setId_customer(doc.getId());
customers.add(customer);
}
} else {
// Log.d(TAG, "Error getting documents: ", task.getException());
}
}
});
firestoreListener = firestoreDB.collection("customer")
.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {
if (e != null) {
// Log.e(TAG, "Listen failed!", e);
return;
}
customers = new ArrayList<>();
for (DocumentSnapshot doc : documentSnapshots) {
Customer customer = doc.toObject(Customer.class);
customer.setId_customer(doc.getId());
customers.add(customer);
}
}
});
id_customer = customers.get(0).getId_customer();
}
and this is my firestore:
You cannot use something now that hasn't been loaded yet. With other words, you cannot simply use the following line of code:
id_customer = customers.get(0).getId_customer();
Outside the onSuccess() method because it will always be null due the asynchronous behaviour of this method. This means that by the time you are trying to use the id_customer variable outside that method, the data hasn't finished loading yet from the database and that's why is not accessible.
A quick solve for this problem would be to use that result only inside the onSuccess() method, or if you want to use it outside, I recommend you see the last part of my anwser from this post in which I have exaplined how it can be done using a custom callback. You can also take a look at this video for a better understanding.