I'm new on Google Firebase and I'm trying to learn something about it.
I'm doing an Android app where you can create a group of person and set the title of the group..then, in the "group page", you can see all your group in a listview.
The structure of my firestore db is something like this:
users --> email(document) ---> Group(collection) --> GroupName(Document) and the group name document contains the partecipants arrayList (partecipant 0 : Name1, partecipant1: name2 etc).
I would like to retrieve the document id(which is the group title) and the arrayList of partecipants, but I don't know of to use the for each in the code...
This is my code:
public void load_list_view(){
String email = getEmail();
final DocumentReference docRef = db.collection("users").document(email).collection("Group").document();
docRef.get()
.addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
titleArray.add(documentSnapshot.getId());
titleString = documentSnapshot.getId();
partecipantsArray.add(documentSnapshot.getString("partecipant"));
num_partecipants = partecipantsArray.size();
numArray.add(num_partecipants);
trash = R.drawable.trash_icon;
firstChar = Character.toString(titleString.charAt(0));
firstCharArray.add(firstChar);
customAdapter = new GroupAdapter(GroupActivity.this, firstCharArray, titleArray, numArray, trash);
listView.setAdapter(customAdapter);
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(GroupActivity.this, e.getStackTrace().toString(), Toast.LENGTH_LONG).show();
}
});
}
with titleArray.add(documentSnapshot.getId()); it retrieve a random ID and I can't understand why.
I haven't found enough documentation on Internet about Arraylist and firestore.
First of all, to get all the documents in a collection you should write your code differently as shown in this documentation.
db.collection("cities")
.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());
}
}
});
Secondly, if you are retrieving an ArrayList you should use (ArrayList<String>) documentSnapshot.get("key") instead of documentSnapshot.getString("key").
Thirdly, you are getting random Id because with this line of code (mentioned below) firebase is generating a new document reference with a random id. Reference Link.
final DocumentReference docRef = db.collection("users").document(email).collection("Group").document();
For your help, I have tweaked your code and you can try this code and check if it's working or not.
public void load_list_view() {
String email = getEmail();
final DocumentReference docRef = firestore.collection("users").document(email);
docRef.collection("Group")
.get()
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
for (QueryDocumentSnapshot document : queryDocumentSnapshots) {
//Extracting Group name from each document
titleString = document.getId();
titleArray.add(titleString);
//Extracting participants ArrayList from each document
partecipantsArray.add((ArrayList<String>) document.get("participant"));
numArray.add(num_partecipants);
firstChar = Character.toString(titleString.charAt(0));
firstCharArray.add(firstChar);
}
num_partecipants = partecipantsArray.size();
numArray.add(num_partecipants);
trash = R.drawable.trash_icon;
firstChar = Character.toString(titleString.charAt(0));
firstCharArray.add(firstChar);
customAdapter = new GroupAdapter(GroupActivity.this, firstCharArray, titleArray, numArray, trash);
listView.setAdapter(customAdapter);
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
//HANDLE EXCEPTION
}
});
}
For People doing in kotlin you can do the following things to get an arraylist from FireStore
First get the ArrayList as String
Remove the char at first and last Index
Split the String at each ','
Convert the list to an Array List
Here is the Code
ArrayList(doc.document.get("id_here").toString().subSequence(1, doc.document.get("id_here").toString().length - 1).split(","))
Also it may have extra spaces so don't forget to use the functions
trimStart() && trimEnd()
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!
}
}
});
I have created a function to add a new user to Firestore Database:
public void addNewUser(String email, String username, String profile_photo){
FirebaseFirestore db = FirebaseFirestore.getInstance(); // this is instantiated here, just to show you
User user = new User(userID, (long) 1, email, StringManipulation.condenseUsername(username), username, profile_photo);
db.collection("Users").add(user)
.addOnSuccessListener(new OnSuccessListener<DocumentReference>() {
#Override
public void onSuccess(DocumentReference documentReference) {
Log.d(TAG, "DocumentSnapshot added with ID: " + documentReference.getId());
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.w(TAG, "Error adding document", e);
}
});
}
And a function to fetch the data from the database, waiting for all the fields to appear in-app.
public UserSettings RetrieveUserSettings(){
Log.d(TAG, "getUserAccountSettings: retrieving user account settings from firebase");
User settings = new User();
DocumentReference userRef;
FirebaseAuth firebaseAuth=FirebaseAuth.getInstance();
try {
userRef = db.collection("Users")
.document(firebaseAuth.getCurrentUser().getUid());
userRef.get()
.addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
if(documentSnapshot.exists())
{
settings.setDisplay_name(documentSnapshot.getString("display_name"));
settings.setUsername(documentSnapshot.getString("username"));
settings.setProfile_photo(documentSnapshot.getString("profile_photo"));
settings.setEmail(documentSnapshot.getString("email"));
settings.setPhone_number(documentSnapshot.getLong("phone_number"));
settings.setUser_id(documentSnapshot.getString("user_id"));
}
else{
Log.d(TAG, "doc not fount in getUserSettinghs ");
}
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.d(TAG, "onFailure: failed to fetch data");
}
});
} catch (NullPointerException e) {
Log.d(TAG, "getUserAccountSettings: NULLPointerException: " + e.getMessage());
}
Log.e(TAG, "getUserAccountSettings: retrieved user_account_settings information: " + settings.toString());
return new UserSettings(settings);
}
When I authenticate, this is the User UID that is generated: E5bBL0D9lCSKy5a0YdUJjuMVuUT2, but when I call the addNewUser function, my Firestore Database looks like this :
, so it is obvious that the User UID generated at authentication is not the same with the document id, which is :
XWwnRBklieJXSxokQuNe.Do you have any idea why this is happening?
As #HenryTwist mentioned in his comment, when using the following line of code:
db.collection("Users").add(user).addOnSuccessListener(/* ... /*);
You are adding a new "User" object to the "Users" collection using a random ID. The above line of code does the same thing as:
db.collection("Users").document().set(user).addOnSuccessListener(/* ... /*);
When you call CollectionReference's add() method or CollectionReference's document() method without passing any parameters, the built-in generator used by Firestore will always generate a random ID each time one of the methods is called.
As I see from the following line of code:
userRef = db.collection("Users").document(firebaseAuth.getCurrentUser().getUid());
You have already implemented Firebase Authentication, which is good. That being said, when you want to add new "User" object to the database, use the UID that comes from authentication process, as shown below:
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
db.collection("Users").document(uid).set(user).addOnSuccessListener(/* ... /*);
In this way, the ID of the document will match the value of the "user_id" property in the database.
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);
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.