Android: Search Query in Firebase - android

I am currently working on an Android project backed by FIREBASE. When I perform querying similar to select statement in SQL, it does not give me the intended result.
My FIREBASE database looks like this:
The code I've used is as follows:
ref = FirebaseDatabase.getInstance().getReference().child("DiscussionForumPosts");
ref.orderByChild("discussionName").equalTo(discussion_name_from_bundle)
.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
DiscussionPostReadModel model = dataSnapshot.getValue(DiscussionPostReadModel.class);
}
//other predefined methods
}
discussion_name_bundle is a string variable that I get from the previous activity.
My DiscussionPostReadModel.java looks like this:
public class DiscussionPostReadModel {
public String discussionName, discussionMessage, userName;
public DiscussionPostReadModel(){}
public DiscussionPostReadModel(String discussionName, String discussionMessage, String userName){
this.discussionName = discussionName;
this.discussionMessage = discussionMessage;
this.userName = userName;
}
public String getDiscussionName(){
return discussionName;
}
public String getDiscussionMessage(){
return discussionMessage;
}
public String getUserName(){
return userName;
}
}
I actually need the system to fetch only the nodes whose discussionName equals the variable discussion_name_from_bundle. instead, it returns to me all the children found in discussionForumPost in the FIREBASE database.
Kindly help me do the functionality of retrieving only the children which satisfies the equality condition. Thank you in advance.

To only retrieve one result you need to also use the limitToFirst(wantedNumberOfResults) method.
You would implement it like this:
ref = FirebaseDatabase.getInstance().getReference().child("DiscussionForumPosts");
ref.orderByChild("discussionName").equalTo(DiscussionForumPosts).limitToFirst(1).addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
DiscussionPostReadModel model = dataSnapshot.getValue(DiscussionPostReadModel.class);
}
//other predefined methods
}

Related

Cannot get the value out of firebase with .getValue()

I am new to Java, Android, and Firebase. What I am trying to do here is read what's already uploaded to firebase, but the code doesn't work. I put a breakpoint and found that it doesn't even run the listener. What is the problem here? Any help is much appreciated.
Here is my database on Firebase:
This is the code I used to retrieve the information from the database.
//in Main Activity
DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference();
//Rest of the code is within onCreate()
mDatabase.child("9099").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String number = dataSnapshot.child("Number").getValue().toString();
String time = dataSnapshot.child("Time").getValue().toString();
String chan1 = dataSnapshot.child("Channel1").getValue().toString();
String chan2 = dataSnapshot.child("Channel2").getValue().toString();
testing.setText(String.format(time));
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});

orderBy child Time

Here is my database and i want to arrange them by time...
My Code
mTimeReference = FirebaseDatabase.getInstance().getReference().child("Messages").child(UID).child(userId);
mTimeReference.orderByChild("Time").addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
String time = dataSnapshot.child("Time").getValue().toString();
String message = dataSnapshot.child("Message").getValue().toString();
LastSeen lastSeeen = new LastSeen();
long lastTime = Long.parseLong(time);
String lastSeenTime = lastSeeen.lastSeen(lastTime, getActivity());
if(lastSeenTime == null) {
holder.setTime("Just Now");
}
else {
holder.setTime(lastSeenTime);
}
holder.setMessage(message);
linearLayoutManager.setStackFromEnd(true);
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
I have an activity where all my friends ids are shown. I want them to be shown in the order of the time in the database (the last they texted).
My present code isn't working.
If you can't figure out the problem at least tell me the how to put an item of a RecyclerView on top. Like if i want to put the friend B on top how do I do it?
You can either order the chats clientside or use an indexed firebase adapter.
For that you need to create an additional structure in your database, as so:
root
- Chats...
- Messages...
- UserActiveChats
- UserId <- your id
- FriendUserId: TimeStamp
- FriendUserId: TimeStamp
Then you have to change your 'Add-Chat-Message (however you implemented it)' function to a WriteBatch which:
Creates the ChatMessage (as now, at /Messages/userId/friendId/..)
Creates/Sets the value at
/UserActiveMessages/userId/friendId:ServerValue.TimeStamp
This way, you can create a query at /UserActiveMessages/myUserId and order it by value (timestamp), which represents the last time they sent a message to you. That way you will have an ordered list of the latest users who sent you a message. Then all you need to do is use a indexed FirebaseRecyclerAdapter to display the actual chats instead of just their userId.
keyQuery = rootReference.child('/UserActiveMessages/userId').orderByValue();
chatsRef = rootReference.child('/Messages/userId/');
FirebaseRecyclerOptions<Chat> options = new FirebaseRecyclerOptions.Builder<Chat>()
.setIndexedQuery(keyQuery, chatsRef, Chat.class)
.build();
see how to implement the rest here: https://github.com/firebase/FirebaseUI-Android/blob/master/database/README.md#using-firebaseui-with-indexed-data

Firebase Realtime Database addChildEventListener fetch all items when app reopen

addValueEventListener gives all the data whenever something changed in the database, due to this I have implemented addChildEventListener to get the only new item when there is a something new in the database.
Currently, the problem I am facing is whenever I open app, addChildEventListener fetch all the item one by one in onChildAdded method.
Is there any way that I can fetch only new items in Firebase Realtime Database? Here is my code:
mDatabase.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
News news = dataSnapshot.getValue(News.class);
Log.i("YES-onChildAdded", news.getId()+"/"+news.getHeadline());
}
#Override
public void onChildChanged(DataSnapshot dataSnapshot, String s) {
News news = dataSnapshot.getValue(News.class);
Log.i("YES-onChildChanged", news.getId()+"/"+news.getHeadline());
}
#Override
public void onChildRemoved(DataSnapshot dataSnapshot) {
News news = dataSnapshot.getValue(News.class);
Log.i("YES-onChildRemoved", news.getId()+"/"+news.getHeadline());
}
#Override
public void onChildMoved(DataSnapshot dataSnapshot, String s) {
News news = dataSnapshot.getValue(News.class);
Log.i("YES-onChildMoved", news.getId()+"/"+news.getHeadline());
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.i("YES-Cancelled", databaseError.getMessage());
}
});
When you attach a listener on a particular DatabaseReference it means that the listener will retrieve all data from that location where the reference points to. Because Firebase database doesn't store metadata you need to add a TIMESTAMP for each record yourself. Defining a certain data then you can create a query to filter your database accordingly. Unfortunately, this is a behaviour that cannot be changed in Fireabse.
Assuming you have a node named item and each item within this node has a TIMESTAMP correctly set, the code to query a database using a TIMESTAMP should look like this:
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
Query query = rootRef.child("item").orderByChild("timestamp");
Further more you can query your database using limitations like this:
Query query = rootRef.child("item")
.orderByChild("timestamp")
.startAt(startingTime)
.endAt(endingTime);

null object reference while trying to retrieve Firebase class Android

I have a model class to store Firebase User information. Inside of the model class I have a HashMap to store all of the data inside. Once I have stored the data, the I push the Hashmap into the Firebase database. The values store fine, but I cannot access the values. Every time I try to access them, I get an error saying that I am attempting to invoke a virtual method on a null object reference.
mDatabase.child("users").child(mUserId).addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot ChildSnapshot, String s) {
// These two lines of code give the error.
User author = ChildSnapshot.child("profile").getValue(User.class);
String author_username = author.getUsername();
These give me the error. I am attempting to grab data from the child of the snapshot. Why is this giving me an error? Is there a better way to do this?
JSON Firebase snapshot:
Model class:
//TODO model class for the user. This way I can set the values for each user. I will be adding more values in the future.
public class User {
public HashMap<String, String> hashMap = new HashMap<String,String>();
public User() {
}
public User(String username) {
hashMap.put("username",username);
}
public String getUsername(){
return hashMap.get("username");
}
}
In case somebody else was struggling with this issue, I wanted to give an answer. Inside of my ChildEventListener, the profile is the key in this situation so when I use ChildSnapshot.child("profile").getValue(User.class) it returns a null value. Also, (I'm not quite sure why this is) the value of the username was stored in a different class called User_message which was used to store the message. so my updated code looks something like this:
mDatabase.child("users").child(mUserId).addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot ChildSnapshot, String s) {
User_message author = ChildSnapshot.getValue(User_message.class);
String author_username = author.getUsername();
I was facing the same problem and spent more than 5 hours. I added Default Constructor of the model and this solves my problem.
public class User {
public String email;
public String name;
public User() {
}
public User(String email, String name) {
this.email = email;
this.name = name;
}}
I hope this will help you. Thanks

DataSnapshot is missing a constructor with no arguments

I am implementing Firebase Recyclerview UI in my application. I have implemented a recyclerview adapter and it shows me following exception.
Following is my adapter code :
FirebaseRecyclerAdapter<DataSnapshot, MyHolder> recyclerAdapter = new FirebaseRecyclerAdapter<DataSnapshot, MyHolder>(
DataSnapshot.class,
R.layout.row_slots,
MyHolder.class,
databaseReference.child("slots").child(uid).child(dayOfWeek).child("time")
) {
#Override
protected void populateViewHolder(MyHolder viewHolder, DataSnapshot model, int position) {
System.out.println("Key : "+model.getKey());
}
};
It is showing following exception :
How can I get a snapshot value using FirebaseRecyclerAdapter?
The problem is DataSnapShot is missing a no Argument Constructor so you can not use it directly like this.
Use some other model class instead.
Like this :
Create your own model called FriendlyMessage :
public class FriendlyMessage {
private String text;
private String name;
// Created constructor with no Arguments
public FriendlyMessage() {
}
public FriendlyMessage(String text, String name) {
this.text = text;
this.name = name;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Most important thing we have created constructor with no Arguments
which was missing in DataSnapShot
NOTE : The above model class is just an example for you as you are new in firebase. You can have your own model class with your own type of parameters and all.
The use it like this for your Firebase Recyclerview :
FirebaseRecyclerAdapter mFirebaseAdapter = new FirebaseRecyclerAdapter<FriendlyMessage, MyHolder>(
FriendlyMessage.class,
R.layout.row_slots,
MyHolder.class,
databaseReference.child("slots").child(uid).child(dayOfWeek).child("time")) {
#Override
protected void populateViewHolder(MyHolder viewHolder, FriendlyMessage friendlyMessage, int position)
{
}
};
EDIT :
It also matter how you are pushing the data on Database. Do it
directly with your model class.
For example for above model FriendlyMessage push it like this :
FriendlyMessage friendlyMessage = new FriendlyMessage("message", "Username");
databaseReference.child(MESSAGES_CHILD).push().setValue(friendlyMessage);
Here your child() will be somewhat different from my implementation it is just an example.
For Listening to a particular DataSnapShot :
databaseReference.child("users").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot postSnapshot : dataSnapshot.getChildren()) {
//The PUSH ID OP WANTED
System.out.println("Push Id ---"+postSnapshot.getKey());
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
})
Explaining the above listener. It will give you the DataSnapShot
Object for your every user who is falling inside your child "users". You can access Push id by getKey() method.
firebaser (and author of the FirebaseUI adapters) here
Lots of good answers already. I'd indeed typically recommend creating a Java class that represents your data objects.
But if you're intent on using a DataSnapshot, you can override FirebaseRecyclerAdapter.parseSnapshot to handle the "conversion":
#Override
protected ChatMessage parseSnapshot(DataSnapshot snapshot) {
return snapshot;
}
When initializing your recyclerAdapter, your passing a DataSnapshot.class as your modelClass, wherein a DataSnapshot doesn't really have a Constructor with no parameters which I think is causing the error, also I think that makes a DataSnapshot an invalid modelClass.
As stated in the FirebaseRecyclerViewAdapter for the modelClass:
modelClass - Firebase will marshall the data at a location into an instance of a class that you provide
You should define your own modelClass by creating an object that suites your needs. There's a simple example on the FirebaseRecyclerViewAdapter link that you can check out. Cheers!
EDIT:
As per the comments, I suggested to have your own modelClass object have a DataSnapshot as a parameter. For a simple example of what I'm saying, refer below.
public class ModelClass {
String sampleString;
ModelClass() {
}
ModelClass(DataSnapshot dataSnapshot) {
// Do what you need from the dataSnapshot here
sampleString = dataSnapshot.child("").toString();
}
}
I think from the example above, you would get what I mean. BUT, I'm not sure if this is recommended nor if it's even acceptable. I haven't tried this out before so I'm also not sure if it'll work.
Since this concern is actually different from the one posted. I suggest posting a different one if ever it doesn't work. Happy Coding. Cheers!

Categories

Resources