Get all usernames in a database SYNCHRONOUSLY - android

So I have a root in the database like this:
users {
"user1" {
username: "username1",
email: "email#email.com"
}
"user2" {
...
}
...
}
Now, I want to register a new user, so for that I need to check if the username that the new user choose is already chosen.
For that I created a single time event and gather all usernames in a string list:
DatabaseReference ref = FirebaseDatabase.getInstance().getReference().child("users");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<String> res = new ArrayList<String>();
Iterable<DataSnapshot> users = dataSnapshot.getChildren();
for (DataSnapshot user : users) {
res.add(user.child("username").getValue(String.class));
}
// No way to return anything
}
#Override
public void onCancelled(DatabaseError databaseError) {
//handle databaseError
}
});
But I have a problem, that method is asynchronous. I need to gather all usernames and know if any exists in that list synchronously.
Is there any way to achieve this?

Related

How to check if a value exists already in a Firebase and get key in android

In my android application, when the user logs in, I need to check my realtime database to determine if the users ID exists within this database. Once the users ID has been located, i then need to retrieve the parent node of this ID in order to determine if the user logging in is a customer or employee. I'm having some difficulties coding this, as i'm relatively new to using firebase.
Here is my code so far:
final String user_id = Objects.requireNonNull(firebaseAuth.getCurrentUser()).getUid();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
ValueEventListener eventListener = new ValueEventListener()
{
#Override
public void onDataChange(DataSnapshot dataSnapshot)
{
for(DataSnapshot ds : dataSnapshot.getChildren())
{
if(ds.child(user_id).exists())
{
//check if employee or customer?
String cust_or_emp = ds.child(user_id).getKey();
Log.d("test1",String.valueOf(ds.child(user_id).getKey()));
if (cust_or_emp.equals("Customers"))
{
name= Objects.requireNonNull(ds.child(user_id).child("User_Information").child("firstName").getValue()).toString();
Log.e("first name is ", "firstname :" + name);
toNextActivity = new Intent(getActivity(), MainActivity.class);
toNextActivity.putExtra("name",name);
Log.e("2first name is ", "firstname :" + name);
progressBarLayout2.setVisibility(View.GONE);
Objects.requireNonNull(getActivity()).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
Objects.requireNonNull(getActivity()).startActivity(toNextActivity);
getActivity().finish();
} else if (cust_or_emp.equals("Employee")) {
//code for if the key is employee
}
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError)
{
Log.d("error", databaseError.getMessage()); //Don't ignore errors!
}
};
rootRef.addListenerForSingleValueEvent(eventListener);
Currently when I run my application, nothing appears to happen.
You're attaching a value listener to the root of your database. Then in your onDataChange you loop over the child node, which means that your ds snapshot is for the Users node, while you seem to think it's for the Employee and Customers node.
The fix should be to listen to the Users node instead:
rootRef.child("Users").addListenerForSingleValueEvent(eventListener);
Your current approach is highly inefficient, as (even when you fix the above) you're loading the entire Users node to check if a specific user exists in there. As you add more users to the app, this means you're loading more and more data, without using it.
A better approach is to check whether the specific user exists under each specific node:
rootRef.child("Users/Employee").child(user_id).addListenerForSingleValueEvent(new new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
... handle the Employee
}
else {
rootRef.child("Users/Customer").child(user_id).addListenerForSingleValueEvent(new new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
... handle the Customer
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
}

How to get key value under a key?

I want to use the spinner to display the key which under specific username but unfortunately it returns nothing to the spinner. I used an array to store the key value which under the username.
Here's my database structure
Let's said I am rexyou0831 and I just want to retrieve the 2 usernames which under my username but my code return me nothing to the list. un is my current username variables. Please if you got any idea please share it with me thank you.
Hers' my code
db = FirebaseDatabase.getInstance();
cref = db.getReference("chat");
public ArrayList<String> retrieve()
{
final ArrayList<String> Student=new ArrayList<>();
cref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot c:dataSnapshot.getChildren())
{
if(c.getKey().equals(un)){
for(DataSnapshot d: dataSnapshot.getChildren()){
Student.add(d.getKey());
}
}else{
Student.clear();
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return Student;
}
To get those usernames under your username, please use the following code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference userRef = rootRef.child("chat").child("rexyou0831");
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<String> list = new ArrayList<>();
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String userName = ds.getKey();
list.add(userName);
}
Log.d("TAG", list);
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
userRef.addListenerForSingleValueEvent(eventListener);
Your out put will be: [gigi1212, mario123]
Note, that onDataChenge() is called asynchronous which means that is called even before you are adding those keys to the list. As a conslusion, you need to declare and use that list, inside onDataChenge(), otherwise is null.

How to fetch particular data from Firebase in Android

I have integrated Google sign-in in my app and i am pushing some data in to fire base including user U-id.I had researched a lot and didn't get anything the problem i am facing that i want to fetch Particular data for eg If User A sign-in and push 5 data and Then User B sign-in and push 3 data.I want a query like if User A sing-in Again it will get his 5 data only and not the data which is pushed by User B.Thanks in Advance :)
By using this it fetch all the data from firebase:
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot data : dataSnapshot.getChildren()) {
FirebaseModel firebasemodel =
data.getValue(FirebaseModel.class);
firebasemodels.add(firebasemodel);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
I have tried all that .child .orderby and .equalTo but did'nt work
My Structure is Like:
My FireBase Structure
You also need a reference to the data, which isn't included in your code block. So something along the lines of (this should be before this):
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference("notepad-secure/notepad");
Firstly add a user_id key in your child data, it will look like below :
id:"",
note:"",
title:"",
user:""
user_id:"{id from which user have you uploaded data}"
And than you can call below function with specific user data like
below Note : "user_id" = id from which user have you uploaded data
DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
Query query = reference.child("notepad").orderByChild("id").equalTo("user_id");
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
// dataSnapshot is the "notepad" node with all children with id
for (DataSnapshot notepad: dataSnapshot.getChildren()) {
// do something with the individual "notepad_data"
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
To Fetch Particular values from the firebase,try this code
FirebaseDatabase database;
database.getReference().child("notepad-secure").orderByChild("id").equalTo(user).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.getValue() != null) {
for (DataSnapshot childSnapshot : dataSnapshot.getChildren()) {
User userdet =childSnapshot.getValue(yourclass.class);
String note=userdet.note;
//Here you will get the string values what you want to fetch
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
First U have to differentiate.U have to implement Firebase Authentication the u can get Firebase UID of every USER.
String userId = FirebaseAuth.getInstance().getCurrentUser().getUid();
Then store seperatly in new node.
i.e Take Firebase Database Instance and
databaserefernace.child("Data").Child("userID);
When your add a user data to Firebase database, you can add it using the specific uid provided by the FirebaseAuth object like this:
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
Assuming you that your database strucure look like this: Firebase root -> notepad-secure -> notepad, to retrieve data, you can use this code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference notepadRef = rootRef.child("notepad-secure").child("notepad").child(uid);
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String id = dataSnapshot.child("id").getValue(String.class);
String note = dataSnapshot.child("note").getValue(String.class);
String title = dataSnapshot.child("title").getValue(String.class);
String user = dataSnapshot.child("user").getValue(String.class);
Log.d("TAG", id + " / " + note + " / " + title + " / " + user);
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
notepadRef.addListenerForSingleValueEvent(eventListener);

Firebase querying data having childs as uid

Users is my root node, in that I have various childs created by getting the uid of the user who authenticated. Within these childs (uid) their are various childs like Info, General maintenance, Complaints.
I want to show some of the details like gCity, gProductModel from General maintenance child from all the users (uids). Each uid will have a different values of gCity, etc. Under General Maintenance, I want to retrieve all that data by setting it on an adapter and listview.
I am not able to retrieve it.
Database image
retreive code
When i am trying to retrieve data from the current user by using 'getuid()'(As shown below) ,its working fine . But when i try to retrieve all users data using' getkey()' , it isn't working .
user = FirebaseAuth.getInstance().getCurrentUser();
ref= FirebaseDatabase.getInstance().getReference("Users")
.child(user.getUid())
.child("General Maintenance");
ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(list_users.size() > 0)
list_users.clear();
for(DataSnapshot postSnapshot:dataSnapshot.getChildren())
{
Generalperson user =
postSnapshot.getValue(Generalperson.class);
list_users.add(user);
}
if(list_users.size() != 0)
{ ListViewAdapter adapter = new
ListViewAdapter(ServicehistoryActivity.this, list_users);
list_data.setAdapter(adapter);}
else
{
list_data.setVisibility(View.INVISIBLE);
k.setVisibility(View.VISIBLE);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Please use this code:
DatabaseReference usersRef = FirebaseDatabase.getInstance().getReference().child("Users");
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.getChildren()) {
String userId = ds.getKey();
DatabaseReference userIdRef = FirebaseDatabase.getInstance().getReference().child("Users").child(userId);
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot ds : dataSnapshot.child("General Maintenence").getChildren()) {
String gCity = ds.child("gCity").getValue(String.class);
String gEmail = ds.child("gEmail").getValue(String.class);
String gPhone = ds.child("gPhone").getValue(String.class);
//and so on
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
userIdRef.addListenerForSingleValueEvent(valueEventListener);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
usersRef.addListenerForSingleValueEvent(eventListener);
If you get this error, Listen at /Users failed: DatabaseError: Permission denied is because you are not authorized to the Database, check the Rules Tab in the Realtime database and make this change:
{
"rules": {
".read": true,
".write":true
}
}
Hope it helps.

Change values in Firebase database nodes by a given criteria

I implemented some kind of chat app using Firebase database. Everything is set and working. Now I am trying to implement functionality that after user name changes all his messages with new username. The Message structure looks like this:
I had success whit this code:
private void changeCurrentUserMessagesUserName(final String newUserName) {
mDatabase.child(RequestParameters.FB_CHILD_MESSAGES) //messages
.orderByChild(RequestParameters.FB_CHILD_USERS_UID) //messageUserUid
.equalTo(mUser.getUid())
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot messageSnapshot : dataSnapshot.getChildren()) {
ChatMessage message = messageSnapshot.getValue(ChatMessage.class);
mDatabase.child(RequestParameters.FB_CHILD_MESSAGES) //messages
.child(message.getMessageNodeKey())
.child(RequestParameters.FB_CHILD_MESSAGES_USERS) //messageUser
.setValue(newUserName);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
//do nothing
}
});
}
But it smells, if there are 100 messages in Firebase that belongs to current user this code will make 100 request to Firebase to change "messageUser" node to every single message.
Anyone could help how to make just one request that?
The link Andre provided has the gist of it: by using a single multi-location update, you can send the entire update in one call. Here's the same approach in Java:
mDatabase
.child(RequestParameters.FB_CHILD_MESSAGES) //messages
.orderByChild(RequestParameters.FB_CHILD_USERS_UID)
.equalTo(mUser.getUid())
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Map<String,Object> updates = new HashMap<String,Object>();
for (DataSnapshot messageSnapshot : dataSnapshot.getChildren()) {
ChatMessage message = messageSnapshot.getValue(ChatMessage.class);
updates.put(
RequestParameters.FB_CHILD_MESSAGES+"/"+
message.getMessageNodeKey()+"/"+
RequestParameters.FB_CHILD_MESSAGES_USERS,
newUserName
);
}
mDatabase.updateChildren(updates);
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
}

Categories

Resources