Get and update Data from Firestore - Problems - java

For my app, I have a lot of occasions, where I need to retrieve and write data to Firestore.
I am able to write new data and to get and display data. I can also overwrite data in one class, but having troubles right now in another one despite using the same method.
FirebaseFirestore db = FirebaseFirestore.getInstance();
FirebaseUser currUser = FirebaseAuth.getInstance().getCurrentUser();
DocumentReference userDocRef = db.collection("Users").document(currUser.getEmail());
//access current values saved under this user
userDocRef.get().addOnSuccessListener(new
OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
User currentUser = documentSnapshot.toObject(User.class);
warmups_skipped = currentUser.getWarmupsSkipped()+1;
Log.d(TAG, "DocumentSnapshot successfully retrieved! " + warmups_skipped);
}
});
I can see in logCat that the local variable is being changed. All good so far.
Then I call this method immediately after:
FirebaseFirestore db = FirebaseFirestore.getInstance();
FirebaseUser currUser = FirebaseAuth.getInstance().getCurrentUser();
DocumentReference userDocRef = db.collection("Users").document(currUser.getEmail());
Map<String, Object> update = new HashMap<>();
update.put(WARMUPSSKIPPED, getWarmups_skipped());
userDocRef
.set(update, SetOptions.merge()).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "Document has been saved");
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.d(TAG, "Document could not be saved");
}
});
}
Also here I get the TAG message displayed, but nothing gets changed in FireStore. I use the exact same second method in another class, where I do not check for, what is already online, but simply overwrite it.
Really appreciate the help!

Okay I figured it out eventually. Apparently I cannot have these two actions separate, so I put the second method inside the first one and now it seems to work. Not entirely sure why, though, cause the variables are class variables and should be accessible from both methods. If anyone else has that problem, here is how it works for me now:
FirebaseFirestore db = FirebaseFirestore.getInstance();
FirebaseUser currUser = FirebaseAuth.getInstance().getCurrentUser();
final DocumentReference userDocRef = db.collection("Users").document(currUser.getEmail());
//access current values saved under this user
userDocRef.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
User currentUser = documentSnapshot.toObject(User.class);
warmups_skipped = currentUser.getWarmupsSkipped()+1;
Map<String, Object> update = new HashMap<>();
update.put(WARMUPSSKIPPED, warmups_skipped);
userDocRef
.set(update, SetOptions.merge()).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Log.d(TAG, "Document has been saved");
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.d(TAG, "Document could not be saved" +e.toString());
}
});
Log.d(TAG, "DocumentSnapshot successfully retrieved! " + warmups_skipped);
}
});

Related

Save current date and user Input to Firebase Firestore

I am making a note-saving app using Firebase Firestore and a RecyclerView.
So far users are able to enter the title and content of the note, this saves and works fine.
What I would like to add is the current date (in a "dd/MM/yy" format) when the user saves the note to be displayed in the recycler view the notes are displayed in.
My code for adding the note is as follows
public class AddWellbeingActivity extends AppCompatActivity {
private static final String TAG = "AddWellbeingActivity";
EditText createtitleofnote, createcontentofnote;
FloatingActionButton savenote;
FirebaseAuth firebaseAuth;
FirebaseUser firebaseUser;
FirebaseFirestore firebaseFirestore;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_wellbeing);
savenote = findViewById(R.id.saveNote);
createcontentofnote = findViewById(R.id.createContentNote);
createtitleofnote = findViewById(R.id.createTitleNote);
firebaseAuth = FirebaseAuth.getInstance();
firebaseFirestore = FirebaseFirestore.getInstance();
firebaseUser = FirebaseAuth.getInstance().getCurrentUser();
savenote.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String title = createtitleofnote.getText().toString();
String content = createcontentofnote.getText().toString();
if(title.isEmpty() || content.isEmpty())
{
Toast.makeText(getApplicationContext(), "Both fields are Required", Toast.LENGTH_SHORT).show();
}
else
{
DocumentReference documentReference = firebaseFirestore.collection("notes").document(firebaseUser.getUid()).collection("myNotes").document();
Map<String, Object> note = new HashMap<>();
note.put("title",title);
note.put("content", content);
documentReference.set(note).addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid)
{
Toast.makeText(getApplicationContext(), "Wellbeing entry saved", Toast.LENGTH_SHORT).show();
startActivity(new Intent(AddWellbeingActivity.this, WellbeingActivity.class));
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e)
{
Toast.makeText(getApplicationContext(), "Wellbeing entry failed to save", Toast.LENGTH_SHORT).show();
}
});
}
}
});
}
If anyone has a solution it would be greatly appreciated
To add a timestamp field when add a note into Firestore, then you should add an extra put() call:
note.put("title",title);
note.put("content", content);
note.put("date", FieldValue.serverTimestamp()); 👈

When uploading a image for one user to firebase storage, the link of the image updates for every user in database

I'm creating this app in Android Studio using Firebase Realtime Database and Firebase Storage. When a user registers through my app the data will store in the Firebase Realtime Database. Then on the profile page, there is a place to upload a picture. When a user uploads a picture it will store in the firebase storage and the link will update in the database on a new field under the respective user.
It worked correctly the last time I checked. But when I added a new user and uploaded his profile picture, that link updates on every other user as well. But in the Firebase Storage, there were no changes. It only happens in Firebase Realtime Database. I couldn't find any solution to this.
This is the part I update the link of the profile.
private void UploadProfPic(Uri image_uri) {
final StorageReference strRef = storageReference.child("users/"+ email_i +"/profile.jpg");
strRef.putFile(image_uri).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Toast.makeText(getApplicationContext(), "Image has been uploaded", Toast.LENGTH_LONG).show();
strRef.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
Picasso.get().load(uri).fit().into(profPic);
imgRef = uri.toString();
usrRF.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for(DataSnapshot dss : snapshot.getChildren()){
String key = dss.getKey();
Map<String, Object> updates = new HashMap<String, Object>();
updates.put("profile_url", imgRef);
usrRF.child(key).updateChildren(updates);
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
Toast.makeText(getApplicationContext(), "Error", Toast.LENGTH_LONG).show();
}
});
}
});
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull /*#org.jetbrains.annotations.NotNull*/ Exception e) {
Toast.makeText(getApplicationContext(), "Failed to update profile picture", Toast.LENGTH_LONG).show();
}
});
}
here usrRf = FirebaseDatabase.getInstance().getReference("users");
Here is my database structure
Any help will be appreciated. Thank you.
According to your last comment:
Yes, Firebase email Authentication
Then you should consider saving user data, under the UID that comes from the authentication process and not under a pushed ID, as I see in your screenshot now. This means that you should add a User object to the database using:
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference usersRef = rootRef.child("users");
usersRef.child(uid).setValue(userObj).addOnCompleteListener(/* ... /*);
And not using:
usersRef.push().setValue(userObj).addOnCompleteListener(/* ... /*);
That beeing said, to be able to update the image that is uploaded to the node of the logged-in user, then please use the following updated method:
final StorageReference strRef = storageReference.child("users/"+ email_i +"/profile.jpg");
strRef.putFile(image_uri).addOnSuccessListener(new OnSuccessListener<UploadTask.TaskSnapshot>() {
#Override
public void onSuccess(UploadTask.TaskSnapshot taskSnapshot) {
Toast.makeText(getApplicationContext(), "Image has been uploaded", Toast.LENGTH_LONG).show();
strRef.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
Picasso.get().load(uri).fit().into(profPic);
imgRef = uri.toString();
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference usersRef = rootRef.child("users");
Map<String, Object> updates = new HashMap<String, Object>();
updates.put("profile_url", imgRef);
usersRef.child(uid).updateChildren(updates).addOnSuccessListener(/* ... /*);
}
});
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull /*#org.jetbrains.annotations.NotNull*/ Exception e) {
Toast.makeText(getApplicationContext(), "Failed to update profile picture", Toast.LENGTH_LONG).show();
}
});
See, there is no for-loop involed? That was causing you trouble, as it was updating all child under "users" node.

addsnapshotlistener triggers even though there is no update in Firebase

In my app, the homepage activity holds a sectioned recyclerview, in which the value is initiated by querying Firebase. The data retrieval and the recyclerview was working well at first.
Then, I tried to implement addsnapshotlistener to automatically update my activity without needing the user to refresh the page independently.
However, when I run my code, the recyclerview repeated the same sectioned recyclerview twice.
Here is the code for my activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().hide();
setContentView(R.layout.homepage);
mAuth = FirebaseAuth.getInstance();
db = FirebaseFirestore.getInstance();
///storageRef = FirebaseStorage.getInstance().getReference();
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
UserId = FirebaseAuth.getInstance().getCurrentUser().getUid();
MainRecyclerView = findViewById(R.id.MainContainer);
SignoutButton = findViewById(R.id.SignOutbutton);
checkUserType();
SignoutButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
FirebaseAuth.getInstance().signOut();
///mAuth.GoogleSignInApi.signOut(apiClient);
Intent i = new Intent(HomePage.this, Login.class);
startActivity(i);
}
});
///queries data from firebase
initData();
BottomNavigationView bottomNavigationView = findViewById(R.id.bottomNavigationView);
bottomNavigationView.setSelectedItemId(R.id.appointment);
bottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()){
case R.id.search:
startActivity(new Intent(getApplicationContext(),Search.class));
overridePendingTransition(0,0);
return true;
case R.id.appointment:
return true;
case R.id.profile:
startActivity(new Intent(getApplicationContext(),Profile.class));
overridePendingTransition(0,0);
return true;
}
return false;
}
});
UpdateToken();
}
#Override
protected void onStart() {
super.onStart();
sectionList.clear();
apnmntList.clear();
CollectionReference colref = db.collection("appointmentsColl").document(UserId)
.collection("Date");
///check for updates inside of the collections
HPListener= colref.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot value, #Nullable FirebaseFirestoreException error) {
for (QueryDocumentSnapshot document : value) {
///query all the values again
db.collection("appointmentsColl").document(UserId)
.collection("Date").document(document.getId())
.collection("appointmentsID")
.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
apnmntList = new ArrayList();
for (DocumentSnapshot querysnapshot: task.getResult()){
apnmtDetails details = new apnmtDetails(
querysnapshot.getString("customer name"),
querysnapshot.getString("barberID"),
querysnapshot.getString("shop name"),
querysnapshot.getString("name"),
querysnapshot.getString("type"),
querysnapshot.getString("status"),
querysnapshot.getString("price"),
querysnapshot.getString("time slot"));
apnmntList.add(details);
section = new Section(document.getString("date"),apnmntList);
}
///notify recyclerview
sectionList.add(section);
mainRecyclerAdapter.notifyDataSetChanged();
}
});
}
}
});
}
#Override
protected void onStop() {
super.onStop();
HPListener.remove();
}
private void checkUserType() {
DocumentReference docRef = db.collection("Users").document(UserId);
docRef.addSnapshotListener(new EventListener<DocumentSnapshot>() {
#Override
public void onEvent(#Nullable DocumentSnapshot value, #Nullable FirebaseFirestoreException error) {
if (value.exists()) {
userType = "Users";
} else {
userType = "Barbers";
}
}
});
}
private void initData(){
db.collection("appointmentsColl").document(UserId)
.collection("Date")
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : task.getResult()) {
///getting the list of appointments and their details
db.collection("appointmentsColl").document(UserId)
.collection("Date").document(document.getId())
.collection("appointmentsID")
.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
apnmntList = new ArrayList();
for (DocumentSnapshot querysnapshot: task.getResult()){
apnmtDetails details = new apnmtDetails(
querysnapshot.getString("customer name"),
querysnapshot.getString("barberID"),
querysnapshot.getString("shop name"),
querysnapshot.getString("name"),
querysnapshot.getString("type"),
querysnapshot.getString("status"),
querysnapshot.getString("price"),
querysnapshot.getString("time slot"));
///adding appointmnets into an arraylist
apnmntList.add(details);
///saving the value of the section title and the appointments arraylist inside one object
section = new Section(document.getString("date"),apnmntList);
}
////initializing a new array list with the section's objects
sectionList.add(section);
///initializes the main recyclerview
LinearLayoutManager manager = new LinearLayoutManager(HomePage.this);
manager.setReverseLayout(true);
manager.setStackFromEnd(true);
MainRecyclerView.setLayoutManager(manager);
MainRecyclerView.setAdapter(mainRecyclerAdapter);
}
});
}
}else{
Toast.makeText(HomePage.this,"failed",Toast.LENGTH_SHORT).show();
}
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.i("Check", e.toString() );
}
});
}
private void UpdateToken() {
FirebaseUser firebaseUser= FirebaseAuth.getInstance().getCurrentUser();
String refreshToken= FirebaseInstanceId.getInstance().getToken();
Token token= new Token(refreshToken);
FirebaseDatabase.getInstance().getReference("Tokens").child(FirebaseAuth.getInstance().getCurrentUser().getUid()).setValue(token);
}
Here is what my output looks like before and after implementing addsnapshotlistener:
Before
After
I tinkered with the addsnapshotlistener for a while because I was not sure whether it is the cause for the problem, so I tried to replace the method inside the addsnapshotlistener with:
finish();
startActivity(getIntent()
I thought this would work, but when I tried to run my code, the homepage started to refresh itself endlessly without stopping.
I tried to search for people with the same problem as my own, but the posts that I find stated that their addsnapshotlistener triggers correctly but return twice the instance of the data.
The method triggers itself when I open my activity, and it triggers itself even if there are no updates in Firebase.
I would appreciate it if anyone can help me with this problem or maybe guide me to any link or post that can help solve my problem.
You mention that your data retrieval was working well at first. Have you changed anything recently?
From reading your code, I cannot see where you are handling any errors you might encounter. A listener may fail due to a security setting change or an invalid query.
It would help if you implemented an error callback to help you better understand what has happened. For example, you can capture the error message as e and output the error.
if (e != null) {
System.err.println("Listen failed: " + e);
return;
}
Documentation:
db.collection("cities")
.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot snapshots,
#Nullable FirestoreException e) {
if (e != null) {
System.err.println("Listen failed: " + e);
return;
}
for (DocumentChange dc : snapshots.getDocumentChanges()) {
if (dc.getType() == Type.ADDED) {
System.out.println("New city: " + dc.getDocument().getData());
}
}
}
});

Android Java FirebaseFirestore Write Error

i am trying to add my auth users in my Cloud Firestore. Here is my code below,
FirebaseFirestore db;
db = FirebaseFirestore.getInstance();
User newUser = new User(nameRegister, surnameRegister, usernameRegister, emailRegister);
db.collection("users")
.add(newUser)
.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);
}
});
I read official Firebase document and did how they suggest.
I can not write my data to db.
Where am I doing wrong? I am waiting for your help and thank you very much in advance.

android firestore: retrieve custom object from HashMap

I would like to store userdata in a document in Firestore. To do that I’m using a HashMap:
String userID = mAuth.getCurrentUser().getUid();
User user = new User(stringMail, stringUsername, stringGender, stringBirthday,
stringCountry, registeredOn);
HashMap<String, User> userHashMap = new HashMap<>();
userHashMap.put("userdata", user);
users.document(userID).set(userHashMap, SetOptions.merge())
.addOnSuccessListener(new OnSuccessListener<Void>() {
#Override
public void onSuccess(Void aVoid) {
Toast.makeText(RegisterActivity.this, "Upload completed to Firestore!", Toast.LENGTH_LONG).show();
}
}).addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(RegisterActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
}
});
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Toast.makeText(RegisterActivity.this, e.getMessage(), Toast.LENGTH_LONG).show();
}
});
That works pretty good. I do have a problem though with retrieving the data. As the data is stored in a HashMap I can’t use following code:
String userID = mAuth.getUid();
users.document(userID).get()
.addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
Map<String, Object> userHashMap = new HashMap<String, Object>();
userHashMap = documentSnapshot.getData();
User user = (User) userHashMap.get("userdata");
I also can't use:
User user = documentSnapshot.toObject(User.class);
So I wondered whether someone can suggest a way how to retrieve a custom object from a HashMap? I should also mention that the document will contain a second HashMap.

Categories