Firebase search query not working on android - android

I'm implementing a search in my android app and I can't seem to make it work.
public void loadReleaseData(String name) {
mDatabase.child("releases")
.child("europe")
.child("data").orderByChild("game/name").startAt(name)
.endAt(name+"\uf8ff")
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.hasChildren()) {
Log.d(TAG, "New datasnapshot");
for (DataSnapshot data : dataSnapshot.getChildren()) {
_Release release = data.getValue(_Release.class);
if (release != null) {
// No platform filter set add all releases!
list.add(release);
if (release.getGame() != null) {
Log.d(TAG, "NAME: " + release.getGame().getName());
}
}
mUpcomingGamesAdapter.notifyDataSetChanged();
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
When I remove startAt or endAt either of the two data is shown but not the correct data, but when they're both added in, nothing is show and my log "New datasnapshot" doesn't even get printed. I'm searching on the names of the games I have in my database.
My firebase database:

According to your comments, the reason your code was not working was because the value of the name variable that was passed to startAt() and endAt methods was incorrect.
The key for solving the problem is to pass as an argument to both method the exact same name that exist in the database, in this case you should search the name in lower case.

Related

How do I check if specific child value exists in FireBase (Android)

I have some trouble trying to check if user information is stored already in the FireBase database.
Basically I'm trying to do something stupid like this:
"select user_name from user where user_id="+userID+"
And if the nickname exists it should make the boolean var isFirstTime = false and if it doesn't it should stay true. And after that it should show register box or not.
This is my db:
Firebase
And this is my code in onCreate method:
databaseReference = FirebaseDatabase.getInstance().getReference();
DatabaseReference dbRefFirstTimeCheck = databaseReference.child("User").child(user.getUid()).child("Nickname");
isFirstTime = true;
dbRefFirstTimeCheck.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.getValue() != null) {
isFirstTime=false;
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
if(isFirstTime) {
showNewUserBox();
}
else {
}
No matter what I do, the methor showNewUserBox() is being called. How do I get the data i need and check if it's there?
As others have commented, data is loaded from Firebase asynchronously. By the time you check isFirstTime, the data hasn't been loaded yet, onDataChange hasn't been run yet, so ifFirstTime will have its default value (false for a boolean).
All code that requires data from the database should be inside onDataChange (or invoked from within there). The simplest fix for your code is:
databaseReference = FirebaseDatabase.getInstance().getReference();
DatabaseReference dbRefFirstTimeCheck = databaseReference.child("User").child(user.getUid()).child("Nickname");
dbRefFirstTimeCheck.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()) {
showNewUserBox();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});
Also see some of the many questions about asynchronous loading from Firebase, such as getContactsFromFirebase() method return an empty list (or this quite old classic: Setting Singleton property value in Firebase Listener).

How to remove specific nodes in firebase real time database

how do you remove an object in firebase without removing entire "simnumbers" child ? for example only remove "LAkUUug..."
First, As per your comment you need to get autogenerated key.For that :-
public String keyval;
FirebaseDatabase.getInstance().getReference().child("numbers-guess-...").child("simnumbers").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot != null && dataSnapshot.getValue() != null) {
// for (DataSnapshot child : dataSnapshot.getChildren()) {
// if we want to get do operation in multiple data then write your code here
// }
keyval = dataSnapshot.getKey());
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
//add code in case you not get proper dat from firebase
}
});
To remove value in firbase you need to use removeValue() and as per my view you should use it with addOnCompleteListener().
Now, add that keyval as a key which you want to remove. show below code:-
FirebaseDatabase.getInstance().getReference()
.child("simnumbers").child(keyval).removeValue()
.addOnCompleteListener(new OnCompleteListener<Void>() {
#Override
public void onComplete(#NonNull Task<Void> task) {
if (task.isSuccessful()) {
//enter your code what you want excute after remove value in firebase.
} else {
//enter msg or enter your code which you want to show in case of value is not remove properly or removed failed.
Toast.makeText(this, "Remove Failed", Toast.LENGTH_SHORT).show();
}
}
});
For deleting you have to use removeValue() method. You have to know the key value of the child otherwise u cant do it. lets say somehow you managed to get the key value which node you want to delete. then just write the code .
FirebaseDatabase.getInstance().getReference().child("simnumbers").child("LAkUUug.....").removeValue();

Firebase / Android - Wait for all thread finish for response

I am have the follow code:
public synchronized void next(final RoomListQueryResultHandler handler) {
this.setLoading(true);
roomList = new ArrayList<Room>();
this.database.child("members").child(this.mUser.getUid()).child("rooms")
.limitToFirst(this.mLimit)
.startAt(this.currentPage * this.mLimit)
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
RoomListQuery.this.setLoading(false);
//mListAdapter.setLoading(false);
if (!dataSnapshot.hasChildren()) {
RoomListQuery.this.currentPage--;
}
for (DataSnapshot ds : dataSnapshot.getChildren()) {
Room room = ds.getValue(Room.class);
//roomList.add(Room.upsert(room));
Room.getRoom(room.getId(), new Room.RoomGetHandler() {
#Override
public void onResult(Room room, customException e) {
if (e != null) {
// Error!
e.printStackTrace();
return;
}
roomList.add(room);
}
});
handler.onResult(roomList, (customException) null);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
handler.onResult((List) null, new customException(databaseError.toString()));
}
});
}
}
If they are see, I have two Handlers, at first I call a list of "rooms" from Firebase, and then for each one I get the detail in other query.
The problem is that the response is a empty list, since the function not wait for all query details to be executed for the rooms, so the variable roomList always returns empty.
Any idea what I can implement, or what other methodology to use to solve it?
Thank you very much!
Greetings.
Depending on how your application is structured, you might want to change the database design so that there is no need to perform an additional Firebase query for each room retrieved from the first query.
//mListAdapter.setLoading(false);
If you're creating a list view where each row is from the /members/<user_id>/rooms Firebase node, what are the minimum room attributes necessary to display that list? If it's just a few things like room name, photo url, owner, room_id, etc you might be better off duplicating those from the original source. Then clicking one of those rows can trigger the original additional Firebase query you had as part of Room.getRoom(room.getId(), new Room.RoomGetHandler() { ... });, to navigate to a new screen / display a modal with the full room details once retrieved.
Update
To address your comment about requiring the extra data, in that case, as part of the Room class I would include an extra boolean value _loadedDetails set initially to false. So that for rendering a room within the list, when _loadedDetails is currently false just display a loading spinner. That way you can still perform those additional queries and when completed, update the appropriate Room object within roomList based on the index. Something like this:
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
RoomListQuery.this.setLoading(false);
//mListAdapter.setLoading(false);
if (!dataSnapshot.hasChildren()) {
RoomListQuery.this.currentPage--;
}
int i = 0;
for (DataSnapshot ds : dataSnapshot.getChildren()) {
Room room = ds.getValue(Room.class);
roomList.add(room); // here instead
updateRoom(room, i);
i++;
}
handler.onResult(roomList, (customException) null);
}
...
// outside of the ValueEventListener
public void updateRoom(room, index) {
Room.getRoom(room.getId(), new Room.RoomGetHandler() {
#Override
public void onResult(Room room, customException e) {
if (e != null) {
// Error!
e.printStackTrace();
return;
}
room._loadedDetails = true; // make that publicly accessible boolean, or include a setter method instead
roomList.set(index, room);
}
});
}

How can I check if a value exists already in a Firebase data class Android

I want to check if the bus number already exists in the database of Firebase.
Here's my sample code. I've been searching for the past days but I can't find the right code to do so.
ref = new Firebase(Config.FIREBASE_URL);
postRef = ref.child("BusNumber");
busNum = edtBus.getText().toString().trim();
route1 = route.trim();
seat = edtSeat.getText().toString().trim();
if (!busNum.isEmpty() && !route1.isEmpty() && !seat.isEmpty()) {
postRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.child(busNum).exists()) {
edtBus.setError("Bus number already exists.");
edtBus.setText("");
} else {
busNumber = new BusNumber();
busNumber.setBusNum(busNum);
busNumber.setRoute(route1);
busNumber.setNumSeat(seat);
postRef.push().setValue(busNumber);
edtBus.setText("");
edtSeat.setText("");
Toast.makeText(AddBusActivity.this, "Saving successful!", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onCancelled(FirebaseError firebaseError) {
Toast.makeText(AddBusActivity.this, "Error", Toast.LENGTH_SHORT).show();
Toast.makeText(AddBusActivity.this, firebaseError.getMessage(), Toast.LENGTH_SHORT).show();
}
});
} else {
Toast.makeText(AddBusActivity.this, "Please complete the information", Toast.LENGTH_SHORT).show();
}
Can somebody help me with this matter? Thanks in advance.
Whether the if statement is correct or not, also my problem is why does the postRef.addListenerForSingleValueEvent...doesn't work? I tried to test some toast message but the message won't pop out.
Your approach is wrong.
When you are doing this dataSnapshot.child(busNum).exists(), it's looking for the busNum in the key section, where your keys are -kasajdh....
So instead what you can do is, get the iterable, now when you look for
data.child(busNum).exists() it relates to the value
postRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot data: dataSnapshot.getChildren()){
if (data.child(busNum).exists()) {
//do ur stuff
} else {
//do something if not exists
}
}
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
Rather than getting whole iterable list of data, you can query for exact entry.
postRef = FirebaseDatabase.getInstance().getReference().child("BusNumber");
postRef.orderByChild("busNum").equalTo(busNum)
.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(dataSnapshot.exists()){
//bus number exists in Database
} else {
//bus number doesn't exists.
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
dataSnapshot.child(busNum).getValue() != null
should work.
It is difficult to guess the problem because you do not show how busNum and busNumber are defined and managed. Is busNumber a String?
push() creates a reference to an auto-generated child location. The auto-generated key looks something like -KPB_cS74yoDaKkM9CNB.
The statement postRef.push().setValue(busNumber) stores value busNumber in location BusNumber/<push-generated-key>.
The statement dataSnapshot.child(busNum).exists() tests for the existence of a value at location BusNumber/<busNum>. It will not be true unless busNum is one of the keys created by push().
It's not clear how you want your data structured. If your bus numbers are Strings and are unique, you do not need to generate a key with push(). You could store the existence of bus numbers using:
postRef.child(busNumber).setValue(true)
if(!(dataSnapshot.child("Users").child(busNum).exists()))
and then hashmap object

Android Firebase, simply get one child object's data

I have been looking for a way to get one child object's data in Android Firebase.
I have found things like Firebase retrieve child Android. All the solutions are suggesting using a "ChildEventListener", however I need to get this data at this moment, not when it is moved, deleted, updated, etcetera.
My data is kept in https://.firebaseio.com/users//creation as a string. I figure there must be some simple way to access that without needing to do too much, because if I copy the exact URL to my browser, I can see the: 'creation: "2015/05/31 21:33:55"' right there in my "Firebase Forge Dashboard".
How can I access this without a listener?
Firebase listeners fire for both the initial data and any changes.
If you're looking to synchronize the data in a collection, use ChildEventListener. If you're looking to synchronize a single object, use ValueEventListener. Note that in both cases you're not "getting" the data. You're synchronizing it, which means that the callback may be invoked multiple times: for the initial data and whenever the data gets updated.
This is covered in Firebase's quickstart guide for Android. The relevant code and quote:
FirebaseRef.child("message").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
System.out.println(snapshot.getValue()); //prints "Do you have data? You'll love Firebase."
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
In the example above, the value event will fire once for the initial state of the data, and then again every time the value of that data changes.
Please spend a few moments to go through that quick start. It shouldn't take more than 15 minutes and it will save you from a lot of head scratching and questions. The Firebase Android Guide is probably a good next destination, for this question specifically: https://firebase.google.com/docs/database/android/read-and-write
You don't directly read a value. You can set it with .setValue(), but there is no .getValue() on the reference object.
You have to use a listener. If you just want to read the value once, you use ref.addListenerForSingleValueEvent().
Example:
Firebase ref = new Firebase("YOUR-URL-HERE/PATH/TO/YOUR/STUFF");
ref.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String value = (String) dataSnapshot.getValue();
// do your stuff here with value
}
#Override
public void onCancelled(FirebaseError firebaseError) {
}
});
Source: https://www.firebase.com/docs/android/guide/retrieving-data.html#section-reading-once
just fetch specific node data and its working perfect for me
mFirebaseInstance.getReference("yourNodeName").getRef().addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
Log.e(TAG, "======="+postSnapshot.child("email").getValue());
Log.e(TAG, "======="+postSnapshot.child("name").getValue());
}
}
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.e(TAG, "Failed to read app title value.", error.toException());
}
});
I store my data this way:
accountsTable ->
key1 -> account1
key2 -> account2
in order to get object data:
accountsDb = mDatabase.child("accountsTable");
accountsDb.child("some key").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot snapshot) {
try{
Account account = snapshot.getChildren().iterator().next()
.getValue(Account.class);
} catch (Throwable e) {
MyLogger.error(this, "onCreate eror", e);
}
}
#Override public void onCancelled(DatabaseError error) { }
});

Categories

Resources