I want to use Firebase real-time database in my app project. I want to check if the word which is filled by user exists in database.
Here is my database ss:
Here is my code:
private Button button;
private FirebaseDatabase database;
private DatabaseReference mRef;
private TextView tvResult;
private EditText et1;
et1=(EditText) findViewById(R.id.et1);
button=(Button) findViewById(R.id.btn);
tvResult=(TextView) findViewById(R.id.tvResult);
database=FirebaseDatabase.getInstance();
mRef=database.getReference();
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
city=et1.getText().toString();
Query query = mRef.child("app").orderByChild("cities").equalTo(city);
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
// dataSnapshot is the "issue" node with all children with id 0
String get= dataSnapshot.getValue().toString();
tvResult.setText(get);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {}
});
}
});
As I said, user fills edittext and after clicking a button, I want to show written city in textview if there is in database.
What you have in your cities is a set of values: a collection of values, where each value is unique, and the order doesn't matter. So it's a single property with multiple values. And while NoSQL databases are all about denormalizing the data, this is actually one of the cases where I'd recommend that you normalize it a bit.
In the Realtime Database you'll typically model a mathematical set as this JSON:
cities: {
london: true,
paris: true,
milan: true,
ny: true,
istanbul: true
}
This data structure has the advantage that:
Each city is by definition unique, since keys must be unique in their location. I.e. there's no way to have london in here twice.
Each city is now stored as a separate property, which means you can query for it separately.
For example, if you have a list of say trips where each trip can have a cities node, and you model it as I've shown, you could query for all cities that include New York with:
firebase.database().ref("cities").orderByChild("cities/ny").equalTo(true)
This will technically work, but will perform pretty badly, because of the way Firebase Realtime Database indexes work. For more on that, and an explanation of how to model this to allow the use-case, have a look at my answer here: Firebase query if child of child contains a value.
I definitely recommend that you check Cloud Firestore out. This use-case is precisely one where Firestore recently released some big improvements. In Firestore you can now store your data set in an array:
["london", "paris", "milan", "ny", "istanbul"]
So say that again you have a collection of trips, and for each trip you have a field cities whose value is the array above. You can now query for trips that include New York with:
firebase.firestore().collection("trips").where("cities", "array-contains", "ny")
And unlike with the Realtime Database, on Firestore this query will scale very well. For more on this see the blog post Better Arrays in Cloud Firestore!.
Unfortunately, there is no query in Firebase real-time database that looks something like this:
mRef.child("app").orderByChild("cities").contains(city)
But for small datasets, there is a workaround that can help you solve this, which is by querying the database to get all the value for your cities property and use contains() method like this:
String str1 = dataSnapshot.child("cities").getValue(String.class);
String str2 = "london";
boolean b = str1.toLowerCase().contains(str2.toLowerCase());
If you'll try to print the value of b, you'll see that is true. But the above examples works well enough only for very small datasets, it doesn't work for large datasets and this is because downloading an entire object to search for fields client-side isn't practical. In this case, I recommend use a third-party search service like Algolia.
Related
I want to retrieve Firebase data within a range of say 1 week. I can query and get data for a day like today, but how about for a range of say 1 week? This is the code that am currenly using for retrieving data for a given day
String mDate = DateFormat.getDateInstance().format(new Date());
DatabaseReference reference = FirebaseDatabase.getInstance().getReference("expenses").child(onlineUserId);
Query query = reference.orderByChild("date").equalTo(mDate);
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
myDataList.clear();
for (DataSnapshot snapshot :dataSnapshot.getChildren()){
Data data = snapshot.getValue(Data.class);
myDataList.add(data);
}
todayItemsAdapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
I cannot find a way of retrieving data for a given range. Someone please help.
The Realtime Database is not designed for complex SQL-like queries.
Not sure if your question refers to grouping results by week. If all you need is a set of results that start and on a certain date and end on another date, you can use startAt(...) and endAt(...) like described in this answer or the spec.
If you need anything more complex than that, you need to
either take all results and filter them in your front end/app code
or use a Cloud Function to do the filtering on the server and
passing the results to the front end.
(Not recommended) You can record the week number (i.e. 45_2020) as a separate field in the document, and filter by that. It's messy and you would have to trust that the front end enters correct info in the field.
I am making an Android app in Android Studio and I want to get specific data from the Firebase. I am trying to search through the Firebase Realtime Database to get all of the Users that have a usercode of 1234 and then getting their name. This is how I have it set up in Firebase:
Firebase Setup image link
Since I am searching for the data where the usercode = 1234 it will return (in the datasnapshot) all of the information about Joe and Lily (since they were the two users that had a usercode of 1234), but it shouldn't return information about Kevin. Here is how I did that:
Query getUsers = ref.orderByChild("usercode").equalTo(1234);
getUsers.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){
//User with usercode = 1234 exists
} else {
//User with that Usercode doesn't exist
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
The datasnapshot, if converted to a string would have all of Lily and Joe's information I believe.
What I want to do is get the first user's name (Which would be Joe in this case) from that datasnaphot. My code will then use it through a few tests before going to the second user's name(Which would be Lily) and repeating the tests. Also, if there were 100 Users then I would need to repeat it for every one of those 100 that had a user code of 1234, so I probably need something repeatable.
So somehow I need to find the first value of the child's name from all of the Users that have a usercode of 1234 and then repeat until I get all of the names and run the test on all of them.
I am new to Stackoverflow, so please tell me if I am missing any information that would be helpful in answering the question.
---- EDIT ----
I have now figured out how to do this with Firebase Firestore. It has simpler queries and allows you to do more with the results. If anyone else has the same issue that I stated above, Firebase Firestore is something you might want to try out.
When using the following line of code:
Query getUsers = ref.orderByChild("usercode").equalTo("1234");
You are searching through the Users node, all users that have the usercode property set to "1234". This query will always return no results because you are searching for 1234 as a String and not as a number, as it is stored in the database. The correct query should be:
Query getUsers = ref.orderByChild("usercode").equalTo(1234); //No double quotes
I am trying to understand how firebase data read is count.Is there any way to use hashmap so that whole data read is count as a single read. I have below code currently to fetch data from firebase where I am saving each child value in separate string variable to use in another purpose. Not understanding is it counting as a single read or multiple. is there any better way to do this?
reference.orderByKey().equalTo(bidPosition).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot datas : dataSnapshot.getChildren()) {
if(dataSnapshot.hasChildren() && !bidPosition.isEmpty()){
String eta = datas.child("eta").getValue(String.class);
String riderid = datas.child("uid").getValue(String.class);
String drivierid = datas.child("did").getValue(String.class);
String drivier_ratings = datas.child("dRat").getValue(String.class);
String r_Fare = datas.child("tAmt").getValue(String.class);
}
}
Firebase Realtime Database isn't billed in terms of number of reads. You might be confusing it with Firestore, which is billed, in part, based on the number of documents read.
For Realtime Database, the pricing page makes it clear. You are charged for $5/GB stored (regardless of how it's read), and $1/GB downloaded. How you download/read the data doesn't matter - it's the total volume that counts. So there is really no way to significantly optimize a read or query operation that fetches some data.
I have the following json tree in my firebase app
--ashWoYViS3SbHtBhLpvStRleBl13
----items
-------- -KxDDW1FYMUOxea5w5ii
------------- description: "gggh"
------------- name: "gggh"
ashWoYViS3SbHtBhLpvStRleBl13 is the userId, obtaineid with FirebaseAuth.getInstance().getUser().getUid();
And -KxDDW1FYMUOxea5w5ii is the key for an item, obtained with the push function before inserting the item in the json tree.
There are more items under the items node, this is only a sample.
Then I want to read all the items to show them in a list in my app. I do the following:
ValueEventListener listener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
List<Item> items= utils.convertChildrenToList(dataSnapshot, Item.class);
getView().setData(customContexts);
getView().showContent();
}
#Override
public void onCancelled(DatabaseError databaseError) {
getView().showError(databaseError.toException(), true);
}
};
Query query = database.getReference("/ashWoYViS3SbHtBhLpvStRleBl13/items")
.orderByKey();
query.addValueEventListener(listener);
At this moment there are 5 items in the list, and after setting the listener with addValueEventListener, I expect to receive the result in onDataChanged only once. What really happens is that I receive infinite calls to onDataChanged every few seconds. The first time the snapshot has the 5 items. The second time the snapshot is empty (null). The third time the snapshot has again the 5 items, and so on, in an infinite loop.
The database is not being updated, because of that I don't understand why I'm becoming more than one callback in onDataChanged. The data is always there, and I don't understand also why the snapshot's value is sometimes null
If I use addListenerForSingleValueEvent instead, then I receive only one result in the callback "onDataChanged". Sometimes the snapshot value is null, sometimes the snapshot has the 5 elements. In any case, it does not solve my problem.
I tried with many versions of the Firebase sdk, from v11.0.2 to firebase 11.4.2, and it happens in all the versions.
The only way to solve the problem I found, is the following.
Instead of registering the listener for the path
"/ashWoYViS3SbHtBhLpvStRleBl13/items", I register a listener for the path
"/some_prefix/ashWoYViS3SbHtBhLpvStRleBl13/items" (and obviously, I save the data using the same prefix too).
Then all works as expected, that is, I receive only on result in the callback "onDataChanged". The snapshot is not null, and I receive the next callbacks only when the data under the items node is really changed.
Or if I use addListenerForSingleValueEvent, then I receive only one callback with all the elements in the node "items".
May you say me what I'm doing wrong here? (because I don't want to use the prefix before the user id).
Thanks in advance.
Every time you want to make a query make the fetched false to make sure that onDatachange read the method but when the method inside the onDataChange want to call onDataChange with accident can't have access because your fetched is true then.
For exemple when you make insertion in onDataChange the method will call them self other time without you calling them.
Boolean fetched = false;
ValueEventListener listener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (fetched == false) {
fetched = true;
List<Item> items = utils.convertChildrenToList(dataSnapshot, Item.class);
getView().setData(customContexts);
getView().showContent();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
getView().showError(databaseError.toException(), true);
}
};
Query query = database.getReference("/ashWoYViS3SbHtBhLpvStRleBl13/items")
.orderByKey();
fetched=false;
query.addValueEventListener(listener);
I am trying to filter my Firebase data, my dataset is complex but here is a sample. I am able to retrieve data just fine but I am unable to filter that data any further using the Firebase queries. Here is a sample dataset:
Here is my query:
private double locStart;
private double locEnd;
Firebase mRef;
Firebase mRef1;
mRef = new Firebase("https://test.firebaseio.com/");
mRef1 = mRef.child("test");
final Intent intent = getIntent();
final Inputs inputs = (Inputs) intent.getSerializableExtra("inputs");
locStart = inputs.getLocLat() - 0.008983;
locEnd = inputs.getLocLat() + 0.008983;
Query filterData = mRef1.orderByChild("locLat").startAt(locStart).endAt(locEnd);
filterData.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Match matchd = dataSnapshot.getValue(Match.class);
Offer.setText(matchd.getfbName());
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
The reference mRef1 retrieves data perfectly, its only when I apply the query to it is when it retrieves null values, the data certainly matches the query, I have even hard coded the values but that does not seem to work either.
Am I missing something I should have setup on the Firebase console? I did setup an index and that solved a warning in my log which was suggesting me to set one up on the field meaning that Firebase is recognising the field and the index as well.
Firebase queries return a subset of the child nodes in a list.
So if you have a list of locations:
locations: {
location1: { lat: 42.010185, lon: -33.010185 },
location2: { lat: -11.19645, lon: 52.461219 },
location3: { lat: 33.14518, lon: -11.128746 }
}
You could query the locations with:
ref.child("locations").orderByChild("lat").startAt(-12.0).endAt(-10)
Your data is missing a level: you're querying test, but are missing the location1, location2, location3 level that I have under it. If you add such a level, your query will be able to match the child.
Your next problem is likely going to be that Firebase Database queries can only order by/filter on a single property. That means that for geo-queries, you can currently only filter on longitude or on latitude, which makes for only half a geo-query. I recommend that you look into GeoFire, which is our library for geo-querying. It combines latitude and longitude of each item into a single geohash value, which can then be queried.