I am doing a simple Registration page and I have a problem. I can't put users' data in the firestore database. I did it with Realtime Database but with firestore there is a problem and I don't know what it is. Here is the code :
CollectionReference UsersRef = FirebaseFirestore.getInstance().collection("Users");
if (UsersRef != null) {
HashMap<String, Object> userDataMap = new HashMap<>();
userDataMap.put("phone",phoneNumber);
userDataMap.put("password",password);
userDataMap.put("name",name);
UsersRef.document(phoneNumber).update(userDataMap).addOnSuccessListener(aVoid -> {
// First TOAST
Toast.makeText(RegisterActivity.this,"Congratulations, your account has been created.",Toast.LENGTH_SHORT).show();
loadingBar.dismiss();
startLoginActivity();
}).addOnFailureListener(e -> {
loadingBar.dismiss();
//SECOND TOAST
Toast.makeText(RegisterActivity.this,"Network error, please try again later",Toast.LENGTH_LONG).show();
});
} else {
Toast.makeText(RegisterActivity.this,"Votre reference USERS n'a pas été créée",Toast.LENGTH_SHORT).show();
}
I'm getting the user's inputs with variables name, phone number, and password.
If everything is fine, the first toast appears.
if the operation didn't work, the second toast appears.
Just for the sake of giving this post an answer:
As Tom Bailey has correctly commented, the code above is using the update() operation. On this official documentation you can find very useful information about the set() and update() operations.
TL:DR
Set(): creates or overwrites a single document. If the document does not exist, it will be created. If the document does exist, its contents will be overwritten with the newly provided data.
Update(): updates some fields of a document without overwriting the entire document.
Related
This question already has answers here:
How to return a list from Firestore database as a result of a function in Kotlin?
(3 answers)
Closed 3 years ago.
I am fairly new to Android development and the Firestore DB, I would greatly appreciate it if someone can point me in the right direction.
I am creating an app that would allow a user to sign in, and I am using their email as the primary identifier for a document in the collection of "users".
I want to be able to check if the users already exists using their email and if they do then return that an account is already registered with that email.
So far I managed to input user data into DB and query the DB to check if the user exists.
However my code overwrites the user with the supplied email rather than ignoring the write request and alerting the user that email already exists.
I already tried creating a private helper boolean function which I will call "checkIfUserExists()" that contains an emailFlag to query the db and change the flag to true if it exists and return the status of the flag, in which I would handle the call to write to the DB based on the result of checkIfUserExists()
//Set on click listener to call Write To DB function
//This is where my writetoDb and checkIfUserExist come together inside my onCreate Method
submitButton.setOnClickListener {
//Check to make sure there are no users registered with that email
if (!checkIfUserExists())
writeUserToDb()
else
Toast.makeText(
this,
"Account already registered with supplied email, choose another.",
Toast.LENGTH_LONG
).show()
}
//This should be called if and only if checkIfUserExists returns false
#SuppressLint("NewApi")
private fun writeUserToDb() {
//User Privilege is initially set to 0
val user = hashMapOf(
"firstName" to firstName.text.toString(),
"lastName" to lastName.text.toString(),
"email" to email.text.toString(),
"password" to password.text.toString(),
"birthDate" to SimpleDateFormat("dd-MM-yyyy", Locale.US).parse(date.text.toString()),
"userPrivilege" to 0,
"userComments" to listOf("")
)
//Create a new document for the User with the ID as Email of user
//useful to query db and check if user already exists
try {
db.collection("users").document(email.text.toString()).set(user).addOnSuccessListener {
Log.d(
TAG,
"DocumentSnapshot added with ID as Email: $email"
)
}.addOnFailureListener { e -> Log.w(TAG, "Error adding document", e) }
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun checkIfUserExists(): Boolean {
var emailFlagExist = false
val userExistQuery = db.collection("users")
userExistQuery.document(email.text.toString()).get()
.addOnSuccessListener { document ->
if (document != null)
Log.w(
TAG,
"Account already exists with supplied email : ${email.text}"
)
emailFlagExist = true
}
return emailFlagExist
//TODO can create a toast to alert user if account is already registered with this email
}
Right now it alerts me that it detected a user with the given email in the DB, however it also overwrites the current user with the recently supplied information after I click on the submit button in the registration page.
How can I prevent this from happening and if you can also point me in the the right direction of best practices for FireStore/Android development I would greatly appreciate it!
the addOnSuccessListener registers a async callback. And checkIfUserExists always returns false, because it finishes before receiving the response from the firebase (the callback execution).
One way to solve this issue, is to put your logic in the callback (call writeUserToDb in your callback method)
Hi I am converting Firestore to FirebaseDatabase, I am able to do most of the conversion except for this one that I came accross. I am stuck at .getdocuments and Documentchanges. I think .getdocuments is .getchildren? I do not know what the equivalent of Documentchanges is in the realtime firebase. Please help. Thanks you in advance!
here is the code i want to convert
firestore.collection("Users")
.get()
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
if (!queryDocumentSnapshots.getDocuments().isEmpty()) {
for (final DocumentChange doc : queryDocumentSnapshots.getDocumentChanges()) {
if (doc.getType() == DocumentChange.Type.ADDED) {
if (!doc.getDocument().getId().equals(mAuth.getCurrentUser().getUid())) {
Friends friends = doc.getDocument().toObject(Friends.class).withId(doc.getDocument().getString("id"));
usersList.add(friends);
usersAdapter.notifyDataSetChanged();
refreshLayout.setRefreshing(false);
}
}
}
if(usersList.isEmpty()){
refreshLayout.setRefreshing(false);
mView.findViewById(R.id.default_item).setVisibility(View.VISIBLE);
}
}else{
refreshLayout.setRefreshing(false);
mView.findViewById(R.id.default_item).setVisibility(View.VISIBLE);
}
}
})
There is no direct equivalent in Realtime Database.
The purpose of documentChanges is to know what changes in a set of query results compared to the last time you got results. This only really applies to when you're using a listener to receive realtime updates (which you are not doing here). If you want to know the changes of a DataSnapshot with respect to the prior DataSnapshot you got in a listener, you will have to figure that out for yourself.
But that's kind of beside the point. Your Firestore code here is unnecessarily using document changes to get a list of documents from a single set of results that don't update in real time. If you're not using a realtime listener, then documentChanges actually isn't really the right thing to use. Every document will appear as "ADDED". For a single set of query results, you should just be iterating the list returned by queryDocumentSnapshots.getDocuments().
The equivalent of getDocuments() for a Realtime Database DataSnapshot is just getChildren(), which will give you a way to iterate the child nodes.
A bit confused why there's no display name being displayed in my Firebase database, I've followed the steps in the example on their website and didn't get the expected result which they showed. Here's the example code.
final Firebase ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com");
ref.authWithPassword("jenny#example.com", "correcthorsebatterystaple",
new Firebase.AuthResultHandler() {
#Override
public void onAuthenticated(AuthData authData) {
// Authentication just completed successfully :)
Map<String, String> map = new HashMap<String, String>();
map.put("provider", authData.getProvider());
if(authData.getProviderData().containsKey("displayName")) {
map.put("displayName", authData.getProviderData().get("displayName").toString());
}
ref.child("users").child(authData.getUid()).setValue(map);
}
#Override
public void onAuthenticationError(FirebaseError error) {
// Something went wrong :(
}
});
Whenever I tried this example code the expected result was to be something similar to what is shown below.
{
"users": {
"6d914336-d254-4fdb-8520-68b740e047e4": {
"displayName": "alanisawesome",
"provider": "password"
},
"002a448c-30c0-4b87-a16b-f70dfebe3386": {
"displayName": "gracehop",
"provider": "password"
}
}
}
Instead of showing something similar to the above, in my database only the provider is shown and not the displayName. Is there any necessary steps required to get the displayName to show or should it be there automatically?
I tried to look into this to see what was included within authData.getProviderData() and this was what was produced in the console when I printed it out.
01-25 17:58:51.921 15651-15651/<package-name> I/System.out: {email=j.joe#hotmail.co.uk, isTemporaryPassword=false, profileImageURL=https://secure.gravatar.com/avatar/de53da9874178adb1a44b392ba5bed2f?d=retro}
So from the result produced it's left me wondering if the key "displayName" was formerly automatically created from the email and stored by default in authData.getProviderData() and that's why it is no longer shown.
Would appreciate it if someone could explain where the displayName in the database comes from because judging by the expected result it seems I've missed something.
Thanks!
An email+password account does not have an associated display name. It only requires an email address and a password.
You can definitely require the user to enter additional information. Just don't pass it to createUser() and don't overwrite it after calling authWithPassword().
Update: since the update to Firebase Authentication released at Google I/O 2016, there is now a display name property for each user. So you can also keep the display name in Firebase Authentication itself (although you won't be able to query/search for it).
I have an app which works with users, and offers the possibility to follow certain users, at the current user choice.
Unfortunately, I don't know how to modify data of a user which is not the current user. I have not seen anything like that stated in the Parse.com docs(or i missed).
I have a column in my database in "Users" class called "usersFollowed" and when the current user clicks "Follow" i want to add the current user to the "usersFollowed" list, but adding them like you will see in the following code does not work.
Follow user code:
dialog = ProgressDialog.show(context, "",
"Following...", true);
viewHolder.userFollow.setSelected(true);
viewHolder.userFollow.setText("FOLLOWING");
ParseQuery<ParseUser> userListQuery = ParseUser.getQuery();
userListQuery.whereEqualTo("screenName", parseUserList.get(position).get("screenName").toString());
userListQuery.findInBackground(new FindCallback<ParseUser>() {
#Override
public void done(List<ParseUser> parseObjects, ParseException e) {
parseUserFollowedList = new ArrayList<>();
if (parseObjects.get(0).getList("usersFollowed") == null) {
parseUserFollowedList.add(ParseUser.getCurrentUser());
parseObjects.get(0).addAll("usersFollowed", parseUserFollowedList);
} else {
parseUserFollowedList = parseObjects.get(0).getList("usersFollowed");
parseUserFollowedList.add(ParseUser.getCurrentUser());
parseObjects.get(0).addAll("usersFollowed", parseUserFollowedList);
}
parseObjects.get(0).saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
dialog.dismiss();
}
});
}
});
.saveInBackground does not work because it throws exception: Cannot save info for user that is not logged in".
Can anyone help me in how to do this?
Cheers!
Users may modify only their own data. But the idea of following can be implemented such that only the currentUser's record requires write access: If Jack chooses to follow Jill, then Jack writes to his "following" relation. This works as long as we don't try to represent "followedBy" in Jill's data (which can be achieved instead with a query).
Or consider that the User table represents the private relationship between a real person and your app. It might make better sense to model the idea of a user's public face with your own custom object, and model following relationships between those. I mention this idea elsewhere here and here.
When I try to save QBCustomObject, response from server sometimes it says
Base forbidden. Need User.
Before saving, I checked QBChatService.getInstance().isLoggedIn() and it returns true.
This error happens for both:
just after logging in
and, for example, 10 minutes afterwards
Disappears after re-launching the app and signing in process.
HashMap<String, Object> fields = new HashMap<String, Object>();
fields.put("name", name);
fields.put("User ID", currentUser.getId());
QBCustomObject qbCustomObject = new QBCustomObject();
qbCustomObject.setUserId(currentUser.getId());
qbCustomObject.setClassName("Group");
qbCustomObject.setFields(fields);
QBCustomObjects.createObject(qbCustomObject, new QBCallbackImpl() {...});
Here are the chain of actions which leads to creating QBCustomObject:
QBAuth.createSession() -> QBUsers.signIn() -> QBChatService.getInstance().loginWithUser()
Why does this error happen?
Seems like I've found the bug. I didn't used the QBUser object I got from .signIn() response. Here is what I mean:
QBUsers.signIn(user, new QBCallbackImpl() {
#Override
public void onComplete(Result result) {
if (result.isSuccess()) {
QBUser signedInUser = (((QBUserResult) result).getUser());
signedInUser.setPassword(password);
//...
loginToChat(signedInUser);
//...
}
});
Chat login and login to Application - they are different logins.
In order to create any object in QuickBlox (except a chat message) - you must act on the user's behalf
More info here how to create a record http://quickblox.com/developers/SimpleSample-customObjects-android#Create_record_using_Android_SDK
There you will find a link how to login a user to application http://quickblox.com/developers/SimpleSample-users-android#Sign_In_.26_Social_authorization
create your session with QBUser.
ex :- QBAuth.createSession(new QBUser("user_name", ""))