I have a Firebase database which I can read from and write to from my Android App. However, I am having problems with one aspect of the read.
Users can set up an account in the App (Firebase email and password) and are taken to a data input screen and save that information to Firebase using this structure:
myAndroidApp
users
21XKq2RXQYZ36l363msI26XOKdn2
description:
emailAddress:
name:
ownerName:
..... etc.
I have a PropertyData Java Class.
The code for saving the data is:
PropertyData propertyData = new PropertyData(ownerName, headline, description....... etc.);
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
databasePropertyData.child(uid).setValue(propertyData);
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot childSnapShot : dataSnapshot.getChildren()) {
String propNameTxt = (String) childSnapShot.child("name").getValue();
String ownerNameTxt = (String) childSnapShot.child("ownerName").getValue();
So that all seems to work fine and I can log in to different test users and write to the Firebase database.
But what I want is for any existing information in the database to be downloaded and populate the data entry form when the user next signs in. The code I have written does this, but when I sign out of the test account and sign into a different one the data entry form is populated by the previous account!! I thought I was using the Uid correctly but obviously not!
When signed into an account if I change the info in the data entry form it does save it to the correct node. So the problem is with the downloading of existing data on startup.
This is the code for downloading existing data to the data entry form:
databasePropertyData = FirebaseDatabase.getInstance().getReference("users");
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
//FirebaseDatabase.getInstance().getReference().child(uid).addValueEventListener(new ValueEventListener() {
//FirebaseDatabase.getInstance().getReference().child("users").child(uid).addValueEventListener(new ValueEventListener() {
FirebaseDatabase.getInstance().getReference().child("users").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot childSnapShot : dataSnapshot.getChildren()) {
String propNameTxt = (String) childSnapShot.child("name").getValue();
String ownerNameTxt = (String) childSnapShot.child("ownerName").getValue();
String headlineTxt = (String) childSnapShot.child("headline").getValue();
String descriptionTxt = (String) childSnapShot.child("description").getValue();
....... etc.
I have tried different variations on the listener without success. Any help/suggestions appreciated.
You cannot use child("users" + uid). To solve this, you have two options:
.child("users").child(uid)
or
child("users/" + uid)
Remember, every node in a Firebase database has it's url.
In order to get the from a single authenticated user, you don't need use getChildren() method. You also don't need to use addValueEventListener, you only need to use addListenerForSingleValueEvent. Please see the following code:
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference uidRef = rootRef.child("users").child(uid);
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String propNameTxt = dataSnapshot.child("name").getValue(String.class);
String ownerNameTxt = dataSnapshot.child("ownerName").getValue(String.class);
String headlineTxt = dataSnapshot.child("headline").getValue(String.class);
String descriptionTxt = dataSnapshot.child("description").getValue(String.class);
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
uidRef.addListenerForSingleValueEvent(eventListener);
You set the database accurate address till where you want to get all the elements on databaseReference as you want. Then get the specific element you want to be store by its unique key Ex :- dataSnapshot.child("name").getValue().toString(); i hope it will help you else reply what you have confusion about firebase connectivity.
private String CurrentUserID;
private DatabaseReference databaseReference
//Outside of Oncreate for user Detection
#Override
protected void onStart(){
super.onStart();
mAuth.addAuthStateListener(mauthListener);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile);
mAuth = FirebaseAuth.getInstance();
mauthListener = new FirebaseAuth.AuthStateListener() {
#Override
public void onAuthStateChanged(#NonNull FirebaseAuth firebaseAuth) {
if (firebaseAuth.getCurrentUser() != null){
CurrentUserID = firebaseAuth.getCurrentUser().getUid();
}
databaseReference = FirebaseDatabase.getInstance().getReference().getRoot().child("myAndroidApp").child("users").child(CurrentUserID);
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String propNameTxt = dataSnapshot.child("name").getValue().toString();
String ownerNameTxt = dataSnapshot.child("ownerName").getValue().toString();
String headlineTxt = dataSnapshot.child("headline").getValue().toString();
String descriptionTxt = dataSnapshot.child("description").getValue().toString();
}
}
}
First of all use ...child("users/" + uid)... instead of ...child("users" + uid).... Because you will get the child "users21XKq2RXQYZ36l363msI26XOKdn2".
Second:
for(DataSnapshot childSnapShot : dataSnapshot.getChildren()) in your listener already gets child one by one in "users/21XKq2RXQYZ36l363msI26XOKdn2". So right now you are trying to get the value of "users/21XKq2RXQYZ36l363msI26XOKdn2/name/name", "users/21XKq2RXQYZ36l363msI26XOKdn2/description/name" and others. I offer you than do it without for cycle.
Like this:
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String propNameTxt = (String) dataSnapshot.child("name").getValue();
String ownerNameTxt = (String) dataSnapshot.child("ownerName").getValue();
String headlineTxt = (String) dataSnapshot.child("headline").getValue();
String descriptionTxt = (String) dataSnapshot.child("description").getValue();
}
Also you can create data class with setters and getters for these parameters (name, ownerName, headline, description) and use it to get all data.
Like this:
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
MyData data = (MyData) dataSnapshot.getValue(MyData.class);
}
Then you can get your field value using getter: data.getName(). I am offering setters and getters because you can insert there some validation.
If you are using data class for Firebase make sure it has an empty constructor.
More about it in my other answer: https://stackoverflow.com/a/48868970/5272951
Related
I have a Firebase database of the following:
Root Node
User node
an automatically generated key generated by ref.push()
attributes
I am trying to retrieve only one of the attributes of a single child under the user. Here is a screenshot of my database:
Screenshot of my database
If you check the screenshot, i only want to retrieve email (assume i have no other way of getting it). However, in the code, I wouldn't know the child of User that contains the email I want. This is what i am currently doing but it is very inefficient (this code checks if my current user exists, if not, it adds his/her data to the database):
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("User");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Iterable<DataSnapshot> children = dataSnapshot.getChildren();
for (DataSnapshot child:children) {
User user1 = child.getValue(User.class);
Log.d("kharas email",user1.getEmail()+"");
if(!user1.getEmail().equals(firebaseAuth.getCurrentUser().getEmail())){
GraphRequest.newMeRequest(token, new GraphRequest.GraphJSONObjectCallback() {
String birthday = "Not Available";
#Override
public void onCompleted(JSONObject object, GraphResponse response) {
User userInfo = new User();
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("User");
birthday = object.has("email")+"";
userInfo.setBirthday(birthday);
userInfo.setEmail(firebaseAuth.getCurrentUser().getEmail());
ref.push().setValue(userInfo);
}
}).executeAsync();
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
I tried to set the child under User to the email but firebase wouldnt let me use some special characters in the key. Any suggestions to make the code more efficient would be appreciated. Or any key suggestions that would make querying easier would be great.
Thanks in advance
Instead of putting random value or auto generated key you can add user's id which is received from fire base
firebaseAuth.getCurrentUser().getUid()
This will be more easy to access and will be more efficient because whenever you get will logged in, you will have this user_id and corresponding to user_id you can get email instead of checking all values in database
The only way to retrieve email if you dont know the random key is this:
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("User");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot datas: dataSnapshot.getChildren()){ for (DataSnapshot child:children) {
String email=datas.child("email").getValue().toString();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Or you can use firebase authentication and add the userid under Users instead of push() then retrieve the userid :
FirebaseUser user=FirebaseAuth.getInstance().getCurrentUser();
String userid=user.getUid();
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("User");
ref.child(userid).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String email=dataSnapshot.child("email").getValue().toString();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
That way you do not have to loop.
I need a help in firebase database,
I am willing to create an app for a city like Kolkata, to find buses between different local stations, I want to save the data in database and user will input where to where they want to go, after clicking on search, list of available data will be shown,
But I need help in how should I save the data to fetch it easily with less complicated code.
You can save data easily with firebase
private void writeNewUser(String userId, String name, String email) {
User user = new User(name, email);
mDatabase.child("users").child(userId).setValue(user);
}
You can search from firebase like below
DatabaseReference mFirebaseDatabaseReference = FirebaseDatabase.getInstance().getReference();
Query query = mFirebaseDatabaseReference.child("users").orderByChild("name").equalTo("Fazal");
query.addValueEventListener(valueEventListener);
ValueEventListener valueEventListener = new ValueEventListener()
{
#Override
public void onDataChange(DataSnapshot dataSnapshot)
{
for (DataSnapshot postSnapshot : dataSnapshot.getChildren())
{
//TODO get the data here
User user = dataSnapshot.getValue(User.class);
}
}
#Override
public void onCancelled(DatabaseError databaseError)
{
}
};
EDIT:
Firebase dont have a great SQL like searches built in. You can either sort by values/key or you can equalto
https://firebase.google.com/docs/database/android/retrieve-data
for further details check fire-base documentation
https://firebase.google.com/docs/database/android/read-and-write
when you write data into firebase database used below code ..
make pojo class for insert data..
public class City {
public String name, code;
public City(String name, String code) {
this.name = name;
this.code = code;
}
}
then after when you insert data into firebase used below code..
private DatabaseReference mFirebaseDatabase;
private FirebaseDatabase mFirebaseInstance;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.register_layout);
mFirebaseDatabase = mFirebaseInstance.getReference("usersDb/UserTable");//define your database name and table name
}
// below method used insert data..
private void insertData(){
City city=new City("Ahmedabad","380016"); // you can add data also runtime.
mFirebaseDatabase.child(city.name).setValue(user);
}
// below method used to search data..
private void sqlQuery(){
DatabaseReference reference = FirebaseDatabase.getInstance().getReference();
Query query = reference.child("usersDb").child("UserTable").orderByChild("name").equalTo("vikas#gmail.com");
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
for (DataSnapshot issue : dataSnapshot.getChildren()) {
Log.d("Value::",issue.getValue(User.class).email);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
I have Firebase data organized in the below format. When I'm trying to fetch data using the below code, it just never enters onDataChange, even though I have data in Firebase at that path.
Please ignore the list part, in the log I am able to see right path of Firebase, i.e.:
conversation/8masp4NLZrYL4HpziIU7uUZjRd73/8masp4NLZrYL4HpziIU7uUZjRd73
DatabaseReference databaseReferenceAdapter = FirebaseDatabase.getInstance().getReference();
DatabaseReference conversation2Ref = databaseReferenceAdapter.child("conversation").child(currentUser).child(userListRef.get(position));
Log.d(TAG,"Data binding++++" + conversation2Ref.getRef().toString());
conversation2Ref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Log.d(TAG,"Data changed");
Conversation conversationInfo = dataSnapshot.getValue(Conversation.class);
mConversationList.add(position,conversationInfo);
Log.d(TAG,"Data changed");
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.d(TAG,"Data error");
}
});
To get those values, instead of using Conversation.cass, you can use the String.class like this:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference yourRef = rootRef.child("conversation").child("8masp4NLZrYL4HpziIU7uUZjRd73").child("8masp4NLZrYL4HpziIU7uUZjRd73");
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String message = dataSnapshot.child("message").getValue(String.class);
long notificationCount = dataSnapshot.child("notificationCount").getValue(Long.class);
long profileId = dataSnapshot.child("profileId").getValue(String.class);
String profileName = dataSnapshot.child("profileName").getValue(String.class);
long time = dataSnapshot.child("time").getValue(String.class);
String type = dataSnapshot.child("type").getValue(String.class);
Log.d("TAG", message);
}
#Override
public void onCancelled(DatabaseError databaseError) {}
};
yourRef.addListenerForSingleValueEvent(eventListener);
child(userListRef.get(position));
The above is wrong, according to the database you have random push() key under the userid. So, you have to retrieve the push key and add it to the child.
to retrieve the key:
String key=conversation2Ref.push().getKey()
then in query do:
child(key)
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);
Bundle bundle = getIntent().getExtras();
String name = bundle.getString("name");
mValueView = (TextView) findViewById(R.id.textView);
mRef = FirebaseDatabase.getInstance()
.getReferenceFromUrl("https://mymap-3fd93.firebaseio.com/Users");
com.google.firebase.database.Query query = mRef.child("Users").orderByChild("title").equalTo(name);
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
//Map<String,Object> map = (Map<String, Object>) dataSnapshot.getValue();
//String Title = (String) map.get("title");
String Title = dataSnapshot.child("title").getValue().toString();
mValueView.setText(Title);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
I want to show object title is same name value.
This is the Firebase database:
If you want to search title value only one time, without listening for updates, you can simply use :
ref.addListenerForSingleValueEvent(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
}});
Then if you get a reference to 'Users' you can do some logic with iteration, for example :
for (DataSnapshot singleSnapshot : dataSnapshot.getChildren()){
String title = (String) singleSnapshot.child("title").getValue();
//do your logic
}
There are two problems in your code:
you're specifying the child node Users twice
a query results a list of results, which your onDataChange doesn't handle
specifying the child node Users twice
mRef = FirebaseDatabase.getInstance()
.getReferenceFromUrl("https://mymap-3fd93.firebaseio.com/Users");
// ^^^^^
Query query = mRef.child("Users").orderByChild("title").equalTo(name);
// ^^^^^
Easily fixed:
mRef = FirebaseDatabase.getInstance()
.getReferenceFromUrl("https://mymap-3fd93.firebaseio.com/");
Query query = mRef.child("Users").orderByChild("title").equalTo(name);
I'm not sure why you use getReferenceFromUrl() to begin with. For most applications, this accomplishes the same is simpler:
mRef = FirebaseDatabase.getInstance().getReference();
a query results a list of results
When you execute a query against the Firebase Database, there will potentially be multiple results. So the snapshot contains a list of those results. Even if there is only a single result, the snapshot will contain a list of one result.
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot: dataSnapshot.getChildren()) {
System.out.println(snapshot.getKey());
System.out.println(snapshot.child("title").getValue(String.class));
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});