using query in android studio for retrieving data from firebase - java

This is my data structure on firebase. I am trying to retrieving first entered data based on double query, but unable to see output.
Here is my code
CarNo = findViewById(R.id.etCar);
myref = FirebaseDatabase.getInstance().getReference("message").child("Member");
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String CarNoEntered = CarNo.getText().toString().trim();
Query checkUser = myref.orderByKey().equalTo(CarNoEntered);
checkUser.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot Dsnapshot) {
if(Dsnapshot.exists()){
Query lastQ = myref.child(CarNoEntered).orderByKey().limitToFirst(1);
lastQ.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
if (snapshot.exists()){
String CarNum = snapshot.child("carNo").getValue(String.class);
String CarNm = snapshot.child("carName").getValue(String.class);
String CarOwner = snapshot.child("owner").getValue(String.class);
String Address = snapshot.child("address").getValue(String.class);
String Mobile = snapshot.child("mobile").getValue(String.class);
String Email = snapshot.child("email").getValue(String.class);
String dt = snapshot.child("date").getValue(String.class);
String wd = snapshot.child("workDone").getValue(String.class);
}
else{
CarNo.setError("Data not Available");
}}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
else{
CarNo.setError("Data not Available");
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}

I see two problems: one just making the code more complex than needed, and one that doesn't work. I'll cover them in turn.
There is never a need to do orderByKey().equalTo(...), you can just use: child(...) for that.
So:
DatabaseReference userRef = myref.child(CarNoEntered);
You then don't even need to listen for the value, but can query for the child node with:
Query lastQ = userRef.orderByKey().limitToFirst(1)
This is now a query for the first child under CarNoEntered.
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.
So in your case lastQ returns a list of one result, and you need to handle that list in your onDataChange method, by looping over snapshot.getChildren():
lastQ.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot childSnapshot: snapshot.getChildren()) {
String CarNum = snapshot.child("carNo").getValue(String.class);
String CarNm = snapshot.child("carName").getValue(String.class);
String CarOwner = snapshot.child("owner").getValue(String.class);
String Address = snapshot.child("address").getValue(String.class);
String Mobile = snapshot.child("mobile").getValue(String.class);
String Email = snapshot.child("email").getValue(String.class);
String dt = snapshot.child("date").getValue(String.class);
String wd = snapshot.child("workDone").getValue(String.class);
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
throw error.toException(); // never ignore errors
}
});

Related

How to read child nodes without mentioning parent node in firebase database within android studio?

I am making an android app using the firebase Realtime database. My rules structure is given below:
{
// Allow anyone to read data, but only authenticated content owners can
// make changes to their data
"rules": {
"Users": {
"$uid": {
".read": true,
// or ".read": "auth.uid != null" for only authenticated users
".write": "auth.uid == $uid"
}
}
}
}
It means that a user should be signed in as an authenticated user to write some data. But when it comes to read no sign in is required.
Now I need to ignore the uid of the user to give free access to other users( i.e. without signing in).
This is the java code I am using currently to read data.
final Intent k = getIntent();
final String school = Objects.requireNonNull(k.getExtras()).getString("School");
final Intent i = getIntent();
final String roll = Objects.requireNonNull(i.getExtras()).getString("Roll");
myRef = myfire.getReference("Users")
.child("GcZoeK7JIbNWVOog6ZjUPiBfxwn2")// **I have problem here.**
.child(school).child(roll);
myRef.child("basic").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
String name = (String) dataSnapshot.child("fb01name").getValue().toString();
String number = (String) dataSnapshot.child("fb04roll").getValue().toString();
if(name == null){
Toast.makeText(getApplicationContext(),"Invalid",Toast.LENGTH_SHORT).show();
}
basic model = new basic(name,number);
tvName.setText(name);
tvRoll.setText(number);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
I could not decide what to write instead of the first child to read any data without signing in.
.child("GcZoeK7JIbNWVOog6ZjUPiBfxwn2")
Please guide me How to ignore this child? Any help will be appreciated.
EDIT
The advice "try to refrain from using deeply nested children" by #Abdullah Z Khan further provided me insight into the problem. I changed my codes as given below :
myfire = FirebaseDatabase.getInstance();
final Intent k = getIntent();
final String school = Objects.requireNonNull(k.getExtras()).getString("School");
final Intent i = getIntent();
final String roll = Objects.requireNonNull(i.getExtras()).getString("Roll");
//--------------------the trick----------------
if (school.equals("224613")){
tvSchool.setText("GcZoeK7JIbNWVOog6ZjUPiBfxwn2");
}else if (school.equals("224614")){
tvSchool.setText("uQx5jDVRp9PV3QpM2FBU6HPq5SJ3");
}
final String uid = tvSchool.getText().toString();
//---------------------------------------------------
myRef = myfire.getReference("Users").child(uid).child(roll);
myRef.child("basic").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
String name = (String) dataSnapshot.child("fb01name").getValue().toString();
String number = (String) dataSnapshot.child("fb04roll").getValue().toString();
if(name == null){
Toast.makeText(getApplicationContext(),"Invalid",Toast.LENGTH_SHORT).show();
}
basic model = new basic(name,number);
tvName.setText(name);
tvRoll.setText(number);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
Although this PLAN B has temporarily relieved me a bit yet the question is still unanswered.Beacuse I have to write the uid code of users each time they join the app( and have to update and publish the app again and again.A better solution is awaited.
EDIT: Added values in >>> marked lines for understanding
From what is given, this is your database structure:
{
"uid": {
"schoolId": {
"roll": {
}
}
}
}
Because it is so much nested (I'd suggest a different hierarchy altogether), there is no
easy way to access a child with an unknown parent as is. However, if you can change the database structure to this:
{
>>> "224614":"GcZoeK7JIbNWVOog6ZjUPiBfxwn2",
"schoolId2":"uid2",
>>> "GcZoeK7JIbNWVOog6ZjUPiBfxwn2": {
"224614": {
"roll": {
}
}
}
}
You'll get a uid lookup table. You can then use that to reach the node. Keep in mind this isn't a direct answer to what you asked, which is how to get a nested node(not value) without knowing the parent, but here you can dynamically access uids of whatever school is needed, assuming each school has exactly one parent.
After that, nest your listener:
myRef = myfire.getReference("Users");
myRef.child(school).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
String uid=dataSnapshot.getValue(String.class);
myRef.child(uid)// **I have problem here.**
.child(school).child(roll);
myRef.child("basic").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
String name = (String) dataSnapshot.child("fb01name").getValue().toString();
String number = (String) dataSnapshot.child("fb04roll").getValue().toString();
if(name == null){
Toast.makeText(getApplicationContext(),"Invalid",Toast.LENGTH_SHORT).show();
}
basic model = new basic(name,number);
tvName.setText(name);
tvRoll.setText(number);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
In practice, try to refrain from using deeply nested children, rather use references to other nodes.
I hope this helps!!
how about this:
final Intent k = getIntent();
final String school = Objects.requireNonNull(k.getExtras()).getString("School");
final Intent i = getIntent();
final String roll = Objects.requireNonNull(i.getExtras()).getString("Roll");
myRef = myfire.getReference("Users")
myRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
String name = (String) dataSnapshot.child(school).child(roll).child("basic").child("fb01name").getValue().toString();
String number = (String) dataSnapshot.child(school).child(roll).child("basic").child("fb04roll").getValue().toString();
if(name == null){
Toast.makeText(getApplicationContext(),"Invalid",Toast.LENGTH_SHORT).show();
}
basic model = new basic(name,number);
tvName.setText(name);
tvRoll.setText(number);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
Well, I don't know if I understood your question, but if you are trying to read the children of all the nodes without specifying them, you can try to do something like the code below: (I didn't test it, I just changed your sample)
myRef = myfire.getReference("Users");
myRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot keySnap : dataSnapshot.getChildren()) {
for (DataSnapshot schoolSnap : keySnap.getChildren()) {
for (DataSnapshot rollSnap : schoolSnap.getChildren()) {
String mRollSnap = rollSnap.getKey();
String name = mRollSnap.child("basic").child("fb01name").getValue().toString();
String number = (String) mRollSnap.child("basic").child("fb04roll").getValue().toString();
if(name == null){
Toast.makeText(getApplicationContext(),"Invalid",Toast.LENGTH_SHORT).show();
}
basic model = new basic(name,number);
tvName.setText(name);
tvRoll.setText(number);
}
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) { }
});

i want to fetch data full in a single Textview from firebase database

I have created a barcode scanner app and it reads the barcode id and needed the output as voice output. in order to read all the things i need to fetch all data together in one single TextView. I did my level best to add the query from database. but it only shows in TextView as com.google.firebase.database.Query#9fc9e4d and my app TTS engine reads it clearly. But i need to set it as all data under a single TextView from database to speak out. please help me???? here only i attached the result handling method.
#Override
public void handleResult(Result result) { final String scanResult = result.getText();
databasefetch = FirebaseDatabase.getInstance().getReference("save");
databasefetch.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
setContentView(R.layout.activity_second);
TextView text = (TextView) findViewById(R.id.textView3);
String tst = databasefetch.child("save").orderByChild("id").equalTo(scanResult).toString();
text.setText(tst);
//text to speech
String toSpeak=text.getText().toString();
//Toast.makeText(getApplicationContext(),toSpeak,Toast.LENGTH_SHORT).show();
txt.speak(toSpeak,TextToSpeech.QUEUE_FLUSH,null);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
Try something like this
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
// TODO: handle the post
YourModelClass object = postSnapshot.getValue(YourModelClass.class);
text.setText(object.getId().equalsIgnoreCase(scanResult) ? object.getDescription() : "");
}
}
No need to run multiple query to filter the data based on id. Check below:
databasefetch = FirebaseDatabase.getInstance().getReference("save");
databasefetch.orderByChild("id").equalTo(scanResult).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
String toSpeak = "";
for (DataSnapshot childSnapshot: dataSnapshot.getChildren()) {
String name = childSnapshot.child("name").getValue(String.class);
String price = childSnapshot.child("price").getValue(String.class);
String details = childSnapshot.child("details").getValue(String.class);
toSpeak = name + ", " + price + ", " + details;
}
text.setText(toSpeak);
txt.speak(toSpeak, TextToSpeech.QUEUE_FLUSH,null);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});

To Fetch Row data fully from FirebaseRealtime-database by checking the product id (child id) with android app scan result id

my app is with barcode scanner and i have created Firebase Realtime-database for the app. i entered some data to database. i want to fetch all the data(name,details,price) in a row by checking the scanresult to the id(in a specific row) in the database. found some tutorials similar to query but i couldn't set code as i wish. please, anyone help me to do this small correction for me ?
below i mentioned my present working code. but it is checking the scanresult with the row unique id and fetched as i want to do. but it is difficult to enter the data with same UID as same as scanresult. This code is working only when i dynamically add data directly to database in site.
The first pic is, of working present code:
the secong pic is to be fetch by checking its id :
#Override
public void handleResult(Result result) {
final String scanResult = result.getText().toString();
setContentView(R.layout.activity_second);
databasefetch = FirebaseDatabase.getInstance().getReference().child("save").child(scanResult);
databasefetch.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
TextView text = (TextView) findViewById(R.id.textView3);
String name = dataSnapshot.child("name").getValue().toString();
String details = dataSnapshot.child("details").getValue().toString();
String price = dataSnapshot.child("price").getValue().toString();
text.setText("\nProduct Name : "+name+"\nDetails : "+details+"\nPrice : "+price);
//text to speech
String toSpeak=text.getText().toString();
//Toast.makeText(getApplicationContext(),toSpeak,Toast.LENGTH_SHORT).show();
txt.speak(toSpeak,TextToSpeech.QUEUE_FLUSH,null);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
To get the data from the second JSON snippet based on its id property, you need to run a query:
databasefetch = FirebaseDatabase.getInstance().getReference().child("save");
Query query = databasefetch.orderByChild("id").equalTo(8901058862836L);
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot: dataSnapshot.getChildren()) {
TextView text = (TextView) findViewById(R.id.textView3);
String name = snapshot.child("name").getValue(String.class);
String details = snapshot.child("details").getValue(String.class);
String price = snapshot.child("price").getValue(String.class);
...
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException(); // never ignore errors
}
})

Firebase data matchmaking

I'm making an app and I need to match data continuously in the activity. I'm using firebase for the database and I'm getting problem of getting my query right. I want to match the data in child(uid) to other data in different child(uid), in this case I'm still testing with only the date.
EDIT: I need to match the child of uid1 (for this case, the date) to ALL EXISTING dates available in the "Schedules". My bad.. the previous question stated was wrong where i said "matching the uid1 data to uid2 data"
Here is my code. I think my conditions aren't correct.
mInstance.getReference("Schedules").addValueEventListener(new ValueEventListener(){
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Schedule schedule = dataSnapshot.child(uid).getValue(Schedule.class);
for(DataSnapshot data: dataSnapshot.getChildren()) {
if (dataSnapshot.child(uid).child("date").exists() && dataSnapshot.child(uid).child("date").getChildrenCount()>= 2) {
test.setText("Found Match for " + schedule.date + "," + schedule.sport + ", and " + schedule.location);
} else {
test.setText(schedule.date + schedule.sport + schedule.location);
}
}
}
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.w(TAG, "Failed to read value.", error.toException());
}
Looking at your database cant a child("date") with children count greater than two.
If i may ask why are doing this?
There are two different approach to solve this problem
Get a list<> of all schedules from database and simply compare uid
or
If you already know the uid of the data you are looking for, get the data from database
More on firebase query
private Query queryGetSchedule;
private Query queryAllSchedule;
private ValueEventListener schedulesListener;
private ValueEventListener allSchedulesListener;
private FirebaseDatabase;
//Inside onCreate or class your are using
this.context = context; //pass in context
this.app = FirebaseApp.initializeApp(context);
this.id = myid;
if(firebaseDatabase == null) firebaseDatabase = FirebaseDatabase.getInstance();
queryGetSchedule = firebaseDatabase.getReference("Schedules").Child("key");
queryAllSchedule = firebaseDatabase.getReference().child("Schedules");
/**
* This will get you a single schedule
*/
public void getSingleSchedules()
{
if(schedulesListener == null)
{
schedulesListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get Post object and use the values to update the UI
if (dataSnapshot.exists()) {
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
// MainActivity.userBook = snapshot.getValue(UserBook.class);
Schedule schedule = snapshot.getValue(Schedule.class);
callback.onUserCallback(userBook);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
// Getting Post failed, log a message
}
};
}
queryGetSchedule.addListenerForSingleValueEvent(schedulesListener);
}
/**
*This will get you all your schedules in a list so you can easily compare
* Let assume you are passing in schedule of interest into this method
*/
public void getAllSchedulesListener(Schedule scheduleOfInterest) {
if(allSchedulesListener == null) {
allSchedulesListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Get Post object and use the values to update the UI
//Use this for list of objects passing in the type
GenericTypeIndicator<List<Schedule>> schedulesList =
new GenericTypeIndicator<List<Schedule>>() {
};
if(dataSnapshot.exists()) {
List<Schedule> mySchedulesList = dataSnapshot.getValue(schedulesList);
//after you get this full list of schedule you can compare with date as a string
for(Schedule schedule: mySchedulesList)
{
if(scheduleOfInterest.date.equals(schedule.date)
{
//found it
//do whatever here
}
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
// Getting Post failed, log a message
}
};
}
queryAllSchedule.addListenerForSingleValueEvent(allSchedulesListener);
}
To solve this, simply use the following lines of code:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference uidOneRef = rootRef.child("Schedules").child(uidOne);
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String dateOne = ds.child("date").getValue(String.class);
Query uidTwoRef = rootRef.child("Schedules").orderByChild("date").equalTo(dateOne);
ValueEventListener eventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String dateTwo = ds.child("date").getValue(String.class);
Schedule schedule = dataSnapshot.getValue(Schedule.class);
if(dateOne.equals(dateTwo)) {
test.setText("Found Match for " + schedule.date + "," + schedule.sport + ", and " + schedule.location);
} else {
test.setText(schedule.date + schedule.sport + schedule.location);
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d(TAG, databaseError.getMessage()); //Don't ignore errors!
}
};
uidTwoRef.addListenerForSingleValueEvent(eventListener);
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d(TAG, databaseError.getMessage()); //Don't ignore errors!
}
};
uidOneRef.addListenerForSingleValueEvent(valueEventListener);
In which uidOne and uidTwo are the id of the users you want to check. I highly recommend you to store the data as a timestamp and not as a String, as it is explained here.

How to retrieve the sibling node's value in firebase?

What I'm trying to do is to return the value of the key named class of the node named m1 with a sibling named name
Here's what my database looked like
Here's what my code looked like
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference().child("Medicines");
final Query userQuery = rootRef.orderByChild("name").equalTo(textView.getText().toString());
userQuery.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
String myParentNode = dataSnapshot.getKey();
for (DataSnapshot child: dataSnapshot.getChildren())
{
String key = child.getKey().toString();
String value = child.getValue().toString();
txt1.setText(myParentNode);
DatabaseReference childRef = FirebaseDatabase.getInstance().getReference().child(myParentNode);
childRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String class_ = dataSnapshot.getValue().toString(); txt2.setText(class_);
}
#Override
public void onCancelled(DatabaseError databaseError) {}
});
}
}
However it just gave me error T.T
Try this:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference().child("Medicines");
final Query userQuery = rootRef.orderByChild("name").equalTo(textView.getText().toString());
userQuery.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot datas: dataSnapshot.getChildren()){
String keys=datas.getKey();
String class=datas.child("class").getValue().toString();
String name=datas.child("name").getValue().toString();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
the datasnasphot is medicines then the query is orderByChild("name").equalTo(textView.getText().toString()); equal to the value that is in the textView.
String keys=datas.getKey(); this will get you the key can be m1 or m2 or m3 depending on the text that you retrieve from the textview.
Then the other two will retrieve the name and the class from the database that are under a specific key.
Try this:
Create a class called Medicine(If you don't already have one) and make it have two String variables name and class and create a constructor, getter and setter methods then use this method:
public String getClassOfMedicineById(String id){
final String medicineClass = "";
FirebaseDatabase.getInstance().getReference("medicine-handbook").child("Medicines")
.child(id)
.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Medicine medicine = dataSnapshot.getValue(Medicine.class);
medicineClass = medicine.get_class();
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
return medicineClass;
}
And then call it like:
getClassOfMedicineById("m1");
Oh and don't call your class getter method getClass(). I think there's a method in the Object class so it might interfere or something.

Categories

Resources