I need to find the existing Child inside the Random Key and I have used OrderByChild() and EqualTo() to filter the queries but it behaves soo weird that for sometimes it showing child exists for only one Child and for sometimes it doesnot work.
i need to check for the child (date_expense) of "February_2019" exist or not? i've tried this
MainActivity
databaseReference = firebaseDatabase.getReference("Expenses_Details");
expensesaddref = databaseReference.child(username).child("Expense_Month").child(monthyr);
int currentInt=Integer.parseInt(currentdate);
numberToWord((currentInt % 100));
Log.d("date_string",String.valueOf(dateString));
final String date_expense=expensesname +"" + dateString;
final ExpenseClass expenses=new ExpenseClass(expensesname,currentdate,date_expense,totalcost);
expensesaddref.orderByChild("date_expense").equalTo(date_expense).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
Toast.makeText(getContext(), "Expense Already exists!!", Toast.LENGTH_SHORT).show();
}
else {
String key = expensesaddref.push().getKey();
expensesaddref.child(key).setValue(expenses);
showListAdd(expensesname);
Log.d("Adding", "Data Adding");
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
}}
Note
if child exist already in db then it should display toast but expense is again adding even though the child is already db
In the Program,
monthYr is February_2019
Currentdate is date of the present day
dateString is date in words(ie one,Eleven,Twenty)
This is the Firebase structure what Iam getting .date_expense is adding even though child is exist already
i have found that the below code working as per my need
ValueEventListener valueEventListener=new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
boolean isTitleAlreadyUsed = false;
for (DataSnapshot ds: dataSnapshot.getChildren()) {
if (ds.hasChild("date_expense") && (expDate.equals(ds.child("date_expense").getValue()))) {
isTitleAlreadyUsed = true;
}
}
if(isTitleAlreadyUsed){
Toast.makeText(getContext(),"Exist",Toast.LENGTH_SHORT).show();
}else
{
String key=expensesaddref.push().getKey();
expensesaddref.child(key).setValue(expenseClass);
showListAdd(lower_exp);
Toast.makeText(getContext(),"Added",Toast.LENGTH_SHORT).show();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
};
expensesaddref.addListenerForSingleValueEvent(valueEventListener);
Related
I know that there is a lot of code on this, but I can't find the solution for my problem.
I have a realtime database :
I have to fetch "saluteBossMassima:"
The way I have declared and initialized my variables:
DatabaseReference databaseMonster;
String id;
databaseMonster=FirebaseDatabase.getInstance().getReference("monster");
id = databaseMonster.push().getKey();
The code that I try:
databaseMonster.child(id).addValueEventListener(newValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String saluteMassimaBossDB = dataSnapshot.child("monster").child("saluteBossMassima").getValue().toString();
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
Anyone can help me?
This won't work:
databaseMonster=FirebaseDatabase.getInstance().getReference("monster");
id = databaseMonster.push().getKey();
When you call push() it generates a new unique key for writing to. There is zero chance that this is the same as the existing key in your screenshot.
If you already know the key of the node you want to read, you should pass that key to child():
// 👇 specify key here
databaseMonster.child("-MtcylP327pK9pUQB54").addValueEventListener(newValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String saluteMassimaBossDB = dataSnapshot.child("saluteBossMassima").getValue(String.class);
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
throw error.toException(); // 👈 never ignore errors
}
});
If you know some value of the node(s) you want to read, but not the key, you can use a query to find the nodes:
// 👇 Use a query to select the nodes with a specific value
Query query = databaseMonster.orderByChild("dannoAttaccoCaricato").equalTo(300);
query.addValueEventListener(newValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// 👇 Loop over the results, since there may be multiple
for (DataSnapshot monsterSnapshot: dataSnapshot.getChildren()) {
String id = monsterSnapshot.getKey();
String saluteMassimaBossDB = monsterSnapshot.child("saluteBossMassima").getValue(String.class);
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
throw error.toException();
}
});
Now we need to loop over dataSnapshot.getChildren(), since there may be multiple nodes with the value of 300 for dannoAttaccoCaricato.
If you know nothing about the node, the best you can do is read all of them and loop over the results:
// 👇 Read all nodes under /monster
databaseMonster.addValueEventListener(newValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot monsterSnapshot: dataSnapshot.getChildren()) {
String id = monsterSnapshot.getKey();
String saluteMassimaBossDB = monsterSnapshot.child("saluteBossMassima").getValue(String.class);
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
throw error.toException();
}
});
Hello everyone i am new on android programming. i have a problem about passind data out of ondatachange method.
as you can see below i have 2 queries get data from firebase query1 gets incomes and query gets data outcomes.
so my problem is total incomes (toplamgelir) and total outcomes (toplamgider) transfer to outside of these queries.
when i want to make result from (totalincomes -minus- totaloutcomes = result)
it doesnt show anything. how can i do that ? i will be appreciate if you show me the way
thank you in advance for your helps.
double toplamgelir, toplamgider;
Query query1 = myRef.orderByChild("gelirZaman")
.startAt(getStartOfDay(today).getTime())
.endAt(getEndOfDay(today).getTime());
query1.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot d : snapshot.getChildren()) {
Gelirler gelirler = d.getValue(Gelirler.class);
gelirler.setGelirid(d.getKey());
toplamgelir = +gelirler.getGelirTutar();
}
TVbugungeliristoc.setText(String.valueOf(toplamgelir) + " TL");
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
Query query2 = myRef2.orderByChild("giderZaman").startAt(getStartOfDay(today).getTime()).endAt(getEndOfDay(today).getTime());
query2.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot d : snapshot.getChildren()) {
Giderler giderler = d.getValue(Giderler.class);
giderler.setGiderid(d.getKey());
toplamgider = +giderler.getGiderTutar();
}
TVbugungideristoc.setText(String.valueOf(toplamgider) + " TL");
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
double result = (toplamgelir-toplamgider);
//textview below shows income-outcome = acquired surplus
TVbugunKarZararistoc.setText(String.valueOf(result));
The problem is not so much where you access the data, but when you access it. By the time your double result = (toplamgelir-toplamgider) runs, the onDataChange methods haven't run yet. If you add some logging, or run in a debugger, you can most easily see that.
Instead of reexplaining why this is, I recommend reading getContactsFromFirebase() method return an empty list and Setting Singleton property value in Firebase Listener.
The tl;dr is: any code that needs data from the database, needs to be inside onDataChange or be called from there.
The simplest way for you to do that with your code, is to move the second listener into the onDataChange for the first one, and then do the final sum in the inner onDataChange:
query1.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot d : snapshot.getChildren()) {
Gelirler gelirler = d.getValue(Gelirler.class);
gelirler.setGelirid(d.getKey());
toplamgelir = +gelirler.getGelirTutar();
}
TVbugungeliristoc.setText(String.valueOf(toplamgelir) + " TL");
Query query2 = myRef2.orderByChild("giderZaman").startAt(getStartOfDay(today).getTime()).endAt(getEndOfDay(today).getTime());
query2.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot d : snapshot.getChildren()) {
Giderler giderler = d.getValue(Giderler.class);
giderler.setGiderid(d.getKey());
toplamgider = +giderler.getGiderTutar();
}
TVbugungideristoc.setText(String.valueOf(toplamgider) + " TL");
double result = (toplamgelir-toplamgider);
TVbugunKarZararistoc.setText(String.valueOf(result));
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
throw error.toException(); // never ignore errors
}
});
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
throw error.toException(); // never ignore errors
}
});
A new alternative is to use the new get() method, instead of addListenerForSingleValueEvent. That returns a Task object, so you can then use Tasks.whenAll(...) to wait for all of them to be done.
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();
}
}
I have the data in firebase as given below:
I want to get the Customer and Device details for each of the Form ID. The Form IDs are generated uniquely by firebase.
I just somehow need to get access to these Form IDs.
I have set the databaseReference as follows:
databaseReference = FirebaseDatabase.getInstance().getReference("users").child(userID).child("forms");
Then I have tried the following code to retrieve the required data:
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot formsSnapshot : dataSnapshot.getChildren()) {
for (DataSnapshot formIDSnapshot : formsSnapshot.getChildren()) {
Device device = formIDSnapshot.getValue(Device.class);
if (device != null) {
// get and use the data
}
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
Update:
I am now successfully able to retrieve the form IDs, thanks to the answer by #Frank.
Now, to get the Device and Customer details I have to write the following code inside the ValueEventListener after getting the form IDs:
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot formsSnapshot : dataSnapshot.getChildren()) {
String formID = formsSnapshot.getKey(); //Retrieving the formID here
//New code addition
// to get the reference to device details node
databaseReference.child(Objects.requireNonNull(formID)).child("Device details").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
Device device = dataSnapshot.getValue(Device.class);
if (device != null) {
// required device details here
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException();
}
});
// to get the reference to customer details node
databaseReference.child(Objects.requireNonNull(formID)).child("Customer details").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
Customer customer = dataSnapshot.getValue(Customer.class);
if (customer != null) {
//required customer details here
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException();
}
});
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException();
}
});
I understand that this is a messy code and I would like to get some cleaner approach for the same.
You can get the key of a node by calling DataSnapshot.getKey(). So to get your form IDs:
databaseReference = FirebaseDatabase.getInstance().getReference("users").child(userID).child("forms");
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot formsSnapshot : dataSnapshot.getChildren()) {
String formID = formsSnapshot.getKey();
Device device = formsSnapshot.getValue(Device.class);
if (device != null) {
// get and use the data
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException(); // never ignore errors
}
});
There is no need for the nested loops. Simply get the children list and loop over it once. At every iteration, cast dataSnapshot to FormID class and afterwards just use its properties.
i would also suggest that you use SingleValueEventListener instead of ValueEventListener if you do not need to observe the data all the time
I'm developing a reservation mobile app wherein when I click the checkAvailability, it will check if the data already exists in the database. My problem is that I don't know how to access since the key is randomly generated. There is a lot of similar questions to mine but no solutions has been working for me.
Firebase Database(Screenshot):
btnAvailability.setOnClickListener
btnAvailability.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Query userQuery = database.getInstance().getReference().child("Requests")
.orderByChild("order/0");
userQuery.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
String type = dataSnapshot.child("checkIn").getValue().toString();
String type2 = dataSnapshot.child("productName").getValue().toString();
if(type.equals(checkInTV.getText().toString()) && type2.equals(beach_name.getText().toString())) {
Toast.makeText(details.this, "Not Available", Toast.LENGTH_SHORT).show();
}else
{
Toast.makeText(details.this, "Available", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
});
From the looks of it, you're trying to check of there is a child that has order/0 with a specific checkIn and productName under Requests. In your current data structure you can do that with:
Query userQuery = database.getInstance().getReference().child("Requests")
.orderByChild("order/0");
userQuery.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot: dataSnapshot.getChildren()) {
String type = snapshot.child("checkIn").getValue().toString();
String type2 = snapshot.child("productName").getValue().toString();
if(type.equals("Saturday, April 20, 2019") && type2.equals("The Mansion")) {
Toast.makeText(details.this, "Not Available", Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(details.this, "Available", Toast.LENGTH_SHORT).show();
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException()
}
});
Differences from your code:
I have a loop inside onDataChange, since a query can have multiple results.
I hardcoded the date to rule out the problem being caused by the way you input the data in the text view.
I handle onCancelled, since ignoring errors is just a bad idea.
A more efficient way to accomplish the same is to have Firebase do part of the query, like this:
Query userQuery = database.getInstance().getReference().child("Requests")
.orderByChild("order/0/checkIn").equalTo("Saturday, April 20, 2019");
userQuery.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot: dataSnapshot.getChildren()) {
String type2 = snapshot.child("productName").getValue().toString();
if(type2.equals("The Mansion")) {
Toast.makeText(details.this, "Not Available", Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(details.this, "Available", Toast.LENGTH_SHORT).show();
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException()
}
});
In here the change is:
I moved part of the check into the query, so that Firebase can perform that filter on the server. This means it has to download less data to the client, making it both faster and cheaper.
You'll still have to filter the second value client-side, since Firebase queries can only order/filter on one property. For more on this, see Query based on multiple where clauses in Firebase.
Note that you're querying double nested data. While you can get this to work for a specific order (orders/0 in this example), if you can have multiple orders in a request, Firebase won't be able to query across all of them.
For more on this and a solution, see: Firebase Query Double Nested
I'd also recommend reading my answers about modeling categories, because I have a feeling you'll need this soon: Firebase query if child of child contains a value
While storing data you need make user email id as first parameter so that you can access data based on user.
{"reuest":{"xyz#gmail.com":{"orders":[{"checkin":"21:29"},{"checkin":"2:19"}]},"abc#gmail.com":{"orders":[{"checkin":"21:29"},{"checkin":"2:19"}]}}}
Finally found a solution on my problem.
btnAvailability.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Query userQuery = database.getInstance().getReference().child("Requests")
.orderByChild("order/0/checkIn").equalTo(checkInTV.getText().toString());
userQuery.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot snapshot: dataSnapshot.getChildren()) {
String type2 = snapshot.child("order/0/productName").getValue().toString();
if(type2.equals(beach_name.getText().toString())) {
Toast.makeText(details.this, "Not Available", Toast.LENGTH_SHORT).show();
}
else {
Toast.makeText(details.this, "Available", Toast.LENGTH_SHORT).show();
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
throw databaseError.toException();
}
});
}
});