I am trying to check uid from firebase Realtime database, but its only returns the current uid and when I try to check uid with previous uid then also it only returns the current uid. I had tried many ways and searched but I can't get the exact solution, please if any one could help.
here what I am using to check the uid
FirebaseAuth.getInstance().getCurrentUser().getUid();
here is my code how I am trying to check
String userEnteredUserName = binding.textLoginUserName.getEditText().getText().toString().trim();
String userEnteredPassword = binding.textPassword.getEditText().getText().toString().trim();
DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Users");
Query checkUser = reference.child(FirebaseAuth.getInstance().getCurrentUser().getUid()).orderByChild("userName").equalTo(userEnteredUserName);
Log.d("uids", "uid: " + uid);
checkUser.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
binding.textLoginUserName.setError(null);
binding.textLoginUserName.setErrorEnabled(false);
Log.d("users", "Username: " + snapshot.toString());
if (snapshot.exists()) {
String passwordFromDB = snapshot.child(userEnteredUserName).child("password").getValue(String.class);
if (passwordFromDB.equals(userEnteredPassword)) {
//next activity
}else{
Toast.makeText(Login.this, "Error", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
Toast.makeText(Login.this, "Error", Toast.LENGTH_SHORT).show();
}
});
In log what I get,
2022-02-06 13:13:06.173 18093-18093/abc C/uids: uid: OFtpR6bfISP3Odd9K1oGWCQmeEf2
Here is my firebase data, "aisha12" is working which is under the current uid but when I try to check "vgbb" it returns only the current uid
If I understand correctly, you are trying to allow a user to register a username and ensuring that the username is unique. Your current data structure doesn't allow you to do that query though.
Firebase Realtime Database can only order/filter on a value that is at a fixed path under each child node of the location you query. So in your current code:
reference.child(FirebaseAuth.getInstance().getCurrentUser().getUid()).orderByChild("userName").equalTo(userEnteredUserName);
You are querying the direct child nodes of /Users/$uid looking for the username under there. Since you're specifying the UID in that path, you're only searching under that specific user.
There is no way with your current data structure to search across all /Users, since the property you are looking for is under /Users/$uid/$username/userName, so with two dynamic keys in there, and the database can only handle one dynamic key.
To allow the query, you will need to change the data structure and remove the $userName level from it, so that you get:
Users: {
"3l6Rm....": {
"userName": "vgbb",
...
},
"OftpR...": {
"userName": "aisha12",
...
}
}
Now you can search for the username with:
DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Users");
Query checkUser = reference.orderByChild("userName").equalTo(userEnteredUserName);
I also recommend checking out these previous questions on allowing a user to register a unique username:
How do you prevent duplicate user properties in Firebase?
Firebase security rules to check unique value of a child #AskFirebase
How to check if usernames are unique in Firebase
unique property in Firebase
How to give unique usernames from a list of usernames to the users in the firebase
Check value already exists or not in Firebase?
Related
I am trying to get and display my user's information when they are logged in. (i.e: name, email, phone)
I have tried multiple snippets i have found on youtube and on stack overflow but they have failed. Most tutorials use realtime Database, which is not what i am looking for.
I have also tried making a "users" object.
private void getData(){
FirebaseFirestore db = FirebaseFirestore.getInstance();
db.collection("users")
//.document(FirebaseAuth.getInstance().getCurrentUser().getUid())
.whereEqualTo("email:", FirebaseAuth.getInstance().getCurrentUser().getUid())
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (DocumentSnapshot document : task.getResult()) {
//Toast.makeText(getApplicationContext(),document.getId() +"==>" + document.getData(),Toast.LENGTH_LONG).show();
//Toast.makeText(getApplicationContext(),""+ document.get("Email") ,Toast.LENGTH_LONG).show();
nameEdt.setText((CharSequence) document.get("First Name"));
emailEdt.setText((CharSequence) document.get("Email"));
phoneEdt.setText((CharSequence) document.get("Phone"));
}
} else {
Toast.makeText(getApplicationContext(),"No such document",Toast.LENGTH_LONG).show();
}
}
});
}
Database Structure:
I understand that documents in firestore are not associated with users, but i dont know how to set my code up so that it only retrieves data from the user that is signed in* It works fine for newly created accounts, but if i were to log out and sign in with a different user it will not update the "account/user information".
In short, how would I access and display my database information from signed in users?
Additional Notes: I am using Email and Password for authentication
To access your user data stored in Firestore, it shouldn't be as complicated as you thought, there's no queries needed, you just need to fetch the documents corresponding to the user's uid, and fetch the specific fields or do whatever you need with them, like this:
db.collection("users").document(FirebaseAuth.getInstance().getCurrentUser().getUid())
.get().addOnCompleteListener(task -> {
if(task.isSuccessful() && task.getResult() != null){
String firstName = task.getResult().getString("First Name");
String email = task.getResult().getString("Email");
String phone = task.getResult().getString("Phone");
//other stuff
}else{
//deal with error
}
});
Original Answer:
User information is not stored in the Firestore database, they are associated with the Firebase Authentication which you set up for the log in. To retrieve the related user information, you need to use the related FirebaseAuth APIs. Use this to retrieve the current log in user:
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
Then you can get the name and email with something like this:
String name = user.getDisplayName();
String email = user.getEmail();
For more information, refer to the documentation.
If FirebaseAuth doesn't resolve, that probably means you didn't follow the set up guides correctly and forgot to include the dependency in your gradle file:
implementation 'com.google.firebase:firebase-auth:17.0.0'
After a couple days head butting at trying to find a solution, i have found one that is able to retrieve user information from the database. However it is important to note that because my application is not holding a lot of data so this structure works for me.
So i was essentially on the right track, but with some lack of understanding of firebase i missed a few concepts.
private void getData(){
FirebaseFirestore db = FirebaseFirestore.getInstance();
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
final String current = user.getUid();//getting unique user id
db.collection("users")
.whereEqualTo("uId",current)//looks for the corresponding value with the field
// in the database
.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (DocumentSnapshot document : task.getResult()) {
nameEdt.setText((CharSequence) document.get("firstName"));
emailEdt.setText((CharSequence) document.get("email"));
phoneEdt.setText((CharSequence) document.get("phone"));
// These values must exactly match the fields you have in your db
}
}
As mentioned before, documents do not associate with users, but you CAN link them together by creating a field in your db called "whatever your want" (i made mine uId). This is because firebase generates a unique id for each user when authenticated. By creating a field that holds that unique id you are able to retrieve the associated information in that collection.
How to create the field:
I created a "user" object that would grab the uid from my edit text. In my code, i passed the uid wherever i was creating/authenticating a new user/account.
FirebaseUser testUser = FirebaseAuth.getInstance().getCurrentUser(); //getting the current logged in users id
String userUid = testUser.getUid();
String uidInput = userUid;
User user = new User(firstNameInput,lastNameInput,uidInput);
db.collection("users").document(userUid)
.set(user)
.addOnSuccessListener(new OnSuccessListener<Void>() {
note: I believe you can also add it to your hash map if you have it done that way.
I'm using the Android SDK to write device tokens to my Firebase database. I am associating these tokens to users. I am assuming that each user may have one or more devices. Hence, this is what my current database structure looks like:
{
"users" : {
"1" : {
"-LAwu8VKATAxifCOZIPn" : "Device_Token_For_User_1",
"-LAwyfXcoLcXBX3rOshb" : "Device_Token_For_User_1"
},
"8" : {
"-LAwuR9cel-p0kXv-LCn" : "Device_Token_For_User_8"
}
}
}
As you can see, User 1 (represented by the key "1") contains the same token that was written twice but with different keys (left side). These keys are generated randomly because of the push() method. I actually only care about the values themselves, but I want to avoid writing the same token to a particular user more than once.
I push the tokens into my database into the Firebase database this way:
String token = FirebaseInstanceId.getInstance().getToken();
Person currentUser;
try {
currentUser = Reservoir.get("current_user", Person.class);
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference();
myRef.child("users").child(Integer.toString(currentUser.id)).push().setValue(token);
} catch (IOException e) {
Log.e("ERROR", "Cannot fetch user from reservoir.");
Toast.makeText(getApplicationContext(), "An unexpected error occurred.", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
All is well, except that when a user logs out and logs in back to the same device, the same token will be pushed twice to the database, which is what happened to User 1.
Instead of using the token as the value you could use it as the key, to ensure it will be unique, and give it an arbitrary value like true.
You would have to change your code like this:
myRef.child("users").child(Integer.toString(currentUser.id)).child(token).setValue(true);
This will result in the following database:
{
"users" : {
"1" : {
"Device_Token_For_User_1" : true,
"SecondDevice_Token_For_User_1" : true
},
"8" : {
"Device_Token_For_User_8" : true
}
}
}
It is better to use the userido, then you can check if the token exists in the database, if it does not exist then you you can add it to the database.
String token = FirebaseInstanceId.getInstance().getToken();
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference();
FirebaseUser user=FirebaseAuth.getInstance().getCurrentUser();
myRef.orderByChild(user.getUid()).equalTo(token).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(!dataSnapshot.exists()){
myRef.child("users").child(user.getUid()).setValue(token);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
I want to create a nickname to each user who login to my app for the first time. The nickname is the user's firstname and I add a number to it from 1 to 9 000 000. For example kevin Bond could get the nickname kevin123456.
I have all the nicknames stored in a node of my firebase database. Two users shouldn't have the same nickname, so I have to check wether the nickname already exists or not in my database. If it already exists, I want to create another nickname until I get a new nickname.
I currently:
- add a listener to the usernickname node
- in onDataChange I have a for loop to create a nickname, then I check if it already exists with dataSnapshot.hasChild(newNickname). If the nickname doesn't exist I do what I want with the nickname and break the for loop, if it exists I loop the for loop to try another nickname. Here is my code:
mFirebaseDatabase.getReference().child("usernickname").orderByKey().addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (int i = 0; i < 9000000; i++) {
final Random random = new Random();
randomNumberId = random.nextInt(9000000);
String newNicknameId = mFirstnameId + String.valueOf(randomNumberId);
//if the nickname already exists we restart the for loop to get a new random number
if (dataSnapshot.hasChild(newNicknameId)) {
i++;
//else if the nickname doesn't exists we create it and stop the loop
} else if (!dataSnapshot.hasChild(newNicknameId)) {
//do what I want...
break;
}
}
}
});
My issue is that I currently have to download all the nicknames node or at least all the nicknames beginning with the user's firstname. It is an issue for me because it could cost me a lot in GB downloaded if I have a lot of users :D
I guess I could use datasnapshot.exists() to check if the nickname exists without having to download all the nicknames, but I don't see how to create another nickname if it already exists. I cannot have a for loop outside of the listener and break it inside of the listener when needed.
Do you see what is the best way to create a new nickname for my users?
Thank you,
Alex
A better approach for unique nicknames would be to append a time stamp to the name:
username + new Date().getTime();
This will add a unique long like 1493808526335 and you can be certain that two users are unlikely to register in the same millisecond with the same name.
You need to use another aproch to check if a user exists. You need to change this line:
dataSnapshot.hasChild(newNicknameId);
with
dataSnapshot.child("userName").getValue().equals(newNicknameId);
In which userName is the name of field in which you store the newNicknameId, assuming your key -> value pair looks like this: userName: "newNicknameId"
Hope it helps.
final Query query = mFirebaseDatabase.getReference().orderByChild("usernickname").equalTo("yourNewNickName");
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
//here means the value exist
//do whatever you want to do
} else {
//here means the value not exist
//do whatever you want to do
}
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
use this will solve your problem. :)
My Firebase Database is like this
When the coding below was run:
String loc=(snapshot.child("loc").getvalue()).tostring();
The output I get has different sequence with the database:
Why is that so?
Firebase data is stored as JSON and is inherently unordered.
If you want to access the data in a specific order, you should specify an orderBy clause for your query and access the data using the snapshot's getChildren() method.
Say you want to log the items by ascending key:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getRef();
Query locations = rootRef.orderByKey();
locations.addListenerForSingleValueEvent(new ValueEventListener() {
public void onDataChange(DataSnapshot snapshot) {
for (DataSnapshot locSnapshot: snapshot.getChildren()) {
System.out.println(locSnapshot.getKey() + ": " + locSnapshot.getValue(String.class));
}
}
public void onCancelled(DatabaseError databaseError) {
Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
// ...
}
});
This sample comes (modified) from the Firebase documentation on reading lists of data.
Frank beat me to my edit, check out his correct solution using orderBy....
You need to use forEach rather than the child method (or child.foreach)
Here is a snippet from the doc:
Because of the way JavaScript Objects work, the ordering of data in
the JavaScript Object returned by val() is not guaranteed to match the
ordering on the server nor the ordering of child_added events. That is
where forEach() comes in handy. It guarantees the children of a
DataSnapshot will be iterated in their query-order.
Source: https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot#forEach
I have a database in Firebase for Android and I have an object with the attributes you see in the image. An object is stored in the database with the following code:
FirebaseUser user = mAuth.getCurrentUser();
String videoId = getIntent().getStringExtra("VIDEO_ID");
minuto = player.getCurrentTimeMillis();
Watching watching = new Watching(user.getUid(), videoId, String.valueOf(minuto));
DatabaseReference mRef = database.getReference().child("Watching").push();
mRef.setValue(watching);
The problem I have is as I am using push() to store the nodes I am having duplicate data as you can see in the image.
Is there any way to avoid storing duplicate data? Knowing that I don't have my own ID to store.
Any help ?
It depends on how you define a duplicate.
A common case where people have this question is when they're storing users. There the definition of a duplicate is simple: if two user objects have the same value for uid, they're the same user. So in that case you should store the users under their uid, instead of under a push ID.
The same applies for your situation. If a single user can only watch a single video, store the nodes under Watching by the uid of the user:
Watching
"NX7...A33"
"idVideo": "b13...o4s"
"minute": "0"
But if it's the combination of uid + idVideo that is unique, store the nodes under a combined key:
Watching
"NX7...A33_b13...o4s": "0"
Now you can easily prevent duplicates, by using setValue() instead of push():
String key = user.getUid() + "_" + videoId;
ref.child("Watching").child(key).setValue(String.valueOf(minuto));
I was facing same problem like you and this is how i figure it out. I m checking email address that user entered with the one saved in my db.if any match found then show toast that email already exists otherwise save with new key.
mFirebaseDatabase.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(final DataSnapshot dataSnapshot) {
for (DataSnapshot data : dataSnapshot.getChildren()) {
//If email exists then toast shows else store the data on new key
if (!data.getValue(User.class).getEmail().equals(email)) {
mFirebaseDatabase.child(mFirebaseDatabase.push().getKey()).setValue(new User(name, email));
} else {
Toast.makeText(ChatListActivity.this, "E-mail already exists.", Toast.LENGTH_SHORT).show();
}
}
}
#Override
public void onCancelled(final DatabaseError databaseError) {
}
});