Android - Firebase searching with filtering - android

I'm developing an app that will help the user to search the books and download them which have been uploaded by other users as a form of the post.
In order to download the books first, the user should search them owing to attribute such as Title.
The posts which meet the requirement of the user should be displayed in the firebase-UI recyclerview.
This is my Firebase data structure:
I want the sample code that will create a Query which returns Id of convenient Posts such as ImgBRr2YFYfAu1WwENS1Ucj6jz13_1514813350760.
Please help me to solve the problem, any suggestions and ideas will be welcomed

Here is what you can do,
For search by language and then filter by title & author
public void search(String languangeSearchString, String title, String author){
FirebaseDatabase.getInstance().getReference().child("Posts").equalTo("language").startAt(languangeSearchString).addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
String id = dataSnapshot.getKey();
if(dataSnapshot.child("title").exists() && dataSnapshot.child("author").exists()){
if(dataSnapshot.child("title").getValue(String.class).equals(title) && dataSnapshot.child("author").getValue(String.class).equals(author)){
//Here are the results
}
}
}
#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) {
}
});
}

To perform searching on firebase-database, we commonly use orderBy(). Like
firebaseDatabase.getReference("Posts").child("postId")
.orderBy("authorId")
But it can't possible to use multiple orderBy() like,
firebaseDatabase.getReference("Posts").child("postId")
.orderBy("authorId")
.orderBy("title") // this will throw an error
.orderBy("language")
So you have to perform searching only on one child-node.
For more info check this Query based on multiple where clauses in Firebase

Related

Android Firebase database limitolast 10 but add up

I'm trying to connect the Firebase real-time database as a database to my app's chats. I know that I can limit the entries that I access to last 10 entries by calling limitToLast(10) function to my Firebase reference.
The problem I have right now is that when I do this, it will limit that reference to always display the last 10 entries even if I add more entries from my app. However, I would want it to count up as I add more entries to my app. So, for instance, if I add 2 more entries, my chat list would show 12 entries and so on.
Here's my code so far with that limitToLast(10) added.
DatabaseReference tRef = database.getReference(getString(R.string.firebase_channel));
tRef.limitToLast(10).addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
Chat c = dataSnapshot.getValue(Chat.class);
chatAdapter.newChat(c, dataSnapshot.getKey());
Log.d(TAG, "onChildAdded\t" + c.asChat());
}
#Override
public void onChildChanged(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
Chat c = dataSnapshot.getValue(Chat.class);
chatAdapter.modifyChat(c, dataSnapshot.getKey());
Log.d(TAG, "onChildChanged\t" + c.asChat());
}
#Override
public void onChildRemoved(#NonNull DataSnapshot dataSnapshot) {
Chat c = chatAdapter.removeChat(dataSnapshot.getKey());
Log.d(TAG, "onChildRemoved\t" + c.asChat());
}
#Override
public void onChildMoved(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
Chat c = dataSnapshot.getValue(Chat.class);
chatAdapter.moveChat(c, dataSnapshot.getKey());
Log.d(TAG, "onChildMoved\t" + c.asChat());
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Log.d(TAG, "onCancelled\t" + databaseError.toException());
Toast.makeText(context, "error loading chat list", Toast.LENGTH_SHORT).show();
}
});
What came through my mind is to actually separate the chat lists into one with which I show in my app and one with which is connected to Firebase, so when a new entry is added in my app, I'll add that to both lists. But I really don't think that using up this extra memory is the solution to this issue. Is there any way to resolve this issue otherwise?
If you only ever want to add items, how about simply ignoring onChildRemoved?

Firebase Database listeners not firing after a while while authenticated

I'm making an app and I've run into a problem with Firebase's Database and Authentication services.
After a while, while I am authenticated (using Firebase Auth) and using my app, my database ValueEventListeners don't seem to be called, even though there is data in the database.
How I'm adding my listeners:
FirebaseDatabase
.getInstance()
.getReference()
.child("my_child")
.addValueEventListener(new ValueEventListener()
{
#Override
public void onDataChange(DataSnapshot dataSnapshot)
{
Log.d("App", "onDataChange");
}
#Override
public void onCancelled(DatabaseError databaseError)
{
}
});
Stuff I've tried:
Checking the database rules (after a relog reading is fine - but simulated reads pass even while authenticated & unauthenticated)
keepSynced(true) on the DatabaseReferences
Adding the listeners in the Activity's onCreate instead of the Application's onCreate
Adding/removing/updating data in the database to trigger a sync
Rebooting
Any help would be much appreciated.
So, apparently the issue was that an API called "Token Service" was not enabled in my Google APIs dashboard.
Thanks to a helpful email from Firebase Support (thanks guys!), I've turned on debug logging by calling FirebaseDatabase.getInstance().setLogLevel(Logger.Level.DEBUG);
Lo and behold: D/PersistentConnection: pc_0 - Error fetching token: An internal error has occurred. [ �Token Service API has not been used in project <project-id> before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/securetoken.googleapis.com/overview?project=<project-id> then retry.
So by enabling the API, it seems to have fixed the error!
Create a reference to your child database, create a custom Chat class as per your requirement( essentially what you see in your firebase ).
addChildEventListener should give you all the changes happening with your my_child. Hope this helps you.
mFirebaseRef = new Firebase("https://yourapp.firebaseio.com/").child("my_child");
/**
* Firebase - Receives message
*/
mFirebaseRef.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
if (dataSnapshot != null && dataSnapshot.getValue() != null) {
try{
Chat model = dataSnapshot.getValue(Chat.class);
mChats.add(model);
mRecyclerView.scrollToPosition(mChats.size() - 1);
mAdapter.notifyItemInserted(mChats.size() - 1);
} catch (Exception ex) {
Log.e(TAG, ex.getMessage());
}
}
}
#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(FirebaseError firebaseError) {
}
});

Proper way of handling messages in chat

I have recently added a chat feature to my app.
I am storing the messages and their timestamps in Firebase database.
I am trying to figure out a way of displaying (in the current chat room) only the last (let's say) 60 messages. This would mean retrieving only the last 60 items of the current conversation from Firebase using limitToLast().
Furthermore I would like to add a Load more button that would appear only when the 60 messages limit has been reached by swiping up and it should load another 60.
Is there a proper way of handling the message archive as I stated above?
Using the code below I actually retrieve the whole specific message archive. I find this ineffective when the specific chat archive has thousands of messages.
mChildEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
ChatMessage chatMessage = dataSnapshot.getValue(ChatMessage.class);
mMessageAdapter.add(chatMessage);
}
#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) {
}
};
mDatabaseReference.child("chat_messages").child(chatId).addChildEventListener(mChildEventListener);
To achieve this, I recomand you using the following logic:
pageEndOffset = 0;
pageLimit = 60;
pageEndOffset += pageLimit;
Query query = mDatabaseReference.child("chat_messages")
.orderByChild("chatId").limitToFirst(pageLimit)
.startAt(pageEndOffset);
query.addValueEventListener(YourActivity.this);
Hope it helps.

Social network - Follow functionality using firebase database

I am building a social network like Instagram. I have worked on many social networks before, using mySQL. I am new to firebase server.
I want to search users via name and want to show the follow/following button on the list view. But I am little confused to run android firebase queries in a standard format. I do not want to run unnecessary loops. Below is my database structure for the follow table.
Node name is follow and follower_id refers to the user who is following the user and user who gets followed is referred as followed_id.
How to write a simple query using android firebase to show all the users with the name starting (e.g "an") and with the status that I am already following him/her or not.
FYI: I am not using firebase rest API's.
How to write a simple query using android firebase to show all the users with the name starting (e.g "an") and with the status that I am already following him/her or not.
I think you can't do it in a single query.
You could try to do it with nested queries, something like this:
ChildEventListener childEventListener = new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
// Retrieve the userId
User user = dataSnapshot.getValue(User.class);
ValueEventListener valueEventListener = new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot usersFollowedDataSnapshot) {
for ( DataSnapshot userFollowedDataSnapshot : usersFollowedDataSnapshot.getChildren() ) {
// Retrieve the follower structure
Follow follow = userFollowedDataSnapshot.getValue(Follow.class);
if ( myUserId == follow.getFollowerId() ) {
// This is a user that I'm following and which name starts with "am"
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
};
Query secondQuery = mFirebaseDatabaseReference.child("follow").orderByChild("followedId").equalTo(user.getId());
secondQuery.addListenerForSingleValueEvent(valueEventListener);
}
#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) {
}
};
Query firstQuery = mFirebaseDatabaseReference.child("users").orderByChild("name").startAt("am").endAt("am\uf8ff");
firstQuery.addChildEventListener(childEventListener);
I know it's not very straightforward and looks disapponting. It could be also slow, but it worth trying.
Alternatively, you should consider to structure your database in a way to simplify the firebase queries.
See more on firebase queries for example here and here.

Update recyclerview item ui in client to indicate that Firebase Database on server got updated

I'm building a chat app using Firebase Realtime Database. I want to implement the functionality like WhatsApp, where the user can send the message without internet (Add the message object on RecyclerView) but will have the clock icon (To show that the message was not sent yet).
When the Firebase Database receives the message (The user device connects to the internet and Firebase sends the message), I want to update the added element on the recyclerview(change the clock icon for a positive icon).
What have I tried? I have that
mFirebaseDatabaseReference = FirebaseDatabase.getInstance().getReference();
mFirebaseAdapter = new ChatFirebaseAdapter(mFirebaseDatabaseReference.child("chat_id"), user.getId());
recyclerChat.setLayoutManager(mLinearLayoutManager);
recyclerChat.setAdapter(mFirebaseAdapter);
My adapter extends FirebaseRecyclerAdapter from firebase-ui-database
I tried to add a addChildEventListener on my DatabaseReference where I get a dataSnapshot of the new element, but I don't know how to get the right position on recyclerview.
mFirebaseDatabaseReference.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
UPDATE RECYCLERVIEW ITEM
}
#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 added an onCompletionListener when I add a new message, but I don't know how get the right position again.
mFirebaseDatabaseReference.push().setValue(message, new DatabaseReference.CompletionListener() {
#Override
public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) {
if (databaseError == null) {
UPDATE RECYCLERVIEW ITEM
}
}
});
Does someone have an idea why I cant accomplish that? Thanks. I search a lot before asked, but I didn't find the right answer.
The solution to your problem lies in adding a delivered boolean which can be set to true and once you receive successful push id from your code in onCompletionListener, then all you need to do is set this boolean to that particular push id.
Now on your android client in your firebase ui you can check if this boolean is set to true and change the state of recycler view items accordingly. This solution will work because firebase database is real-time.
//setting boolean onComplete
mFirebaseDatabaseReference.push().setValue(message, new DatabaseReference.CompletionListener() { #Override public void onComplete(DatabaseError databaseError, DatabaseReference databaseReference) { if (databaseError == null) { databaseReference.child("delivered").setValue(true); } } });
For chat apps like whatsapp, messenger etc you would take another messaging route if not using firebase as backened. Which I am not discussing here as it is out of scope of asked question.

Categories

Resources