Is it possible to specify the which data is read by the FirebaseListAdapter?
At the moment, I could only read the complete database. The database holds a lot of different objects. The object has a value which represents the User who has created the object.
Now, I only want to read the objects from this special user. When I try it like this, there are empty list field.
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReferenceFromUrl("URL");
//HOW CAN I DO THE QUERY FOR THAT DATABASE REFERENCE?
FirebaseListAdapter<Machine> firebaseListAdapter = new FirebaseListAdapter<Machine>(
this,
Machine.class,
R.layout.list_item,
databaseReference) {
#Override
protected void populateView(View v, final Machine model, int position) {
//CAN I DO THIS BY QUERY?
if(model.getS_UserID.equals(user.getID)){
//SOME STUFF WHICH I DO
}
};
}
list.setAdapter(firebaseListAdapter);
The question is, can I do the If-Statement by doing a query for the FirebaseListAdapter?
At the moment, I do something like this:
if(model.getS_UserID.equals(user.getID()) --> DO SOME STUFF
But it also creates some empty fields which are really ugly.
My Database looks like this:
OBJECT
-USERID = STRING
-NAME = ...
-.....
You can pass in a Query to the FirebaseListAdapter instead of the database reference you use right now. To filter on items with the user ID:
DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReferenceFromUrl("URL");
Query query = databaseReference.orderByChild("s_UserId").equalTo(user.getID);
FirebaseListAdapter<Machine> firebaseListAdapter = new FirebaseListAdapter<Machine>(
this,
Machine.class,
R.layout.list_item,
query) {
Read more about this in the Firebase documentation on ordering and filtering data.
Related
Basically what I am trying to do is I have a database with the name users having an attribute username. I have some usernames in one list and I want to show details of these users only whose username is present in the list. How can I write a query to fetch details of those users only whose username is found in this list? And note that there is no lexicographical ordering so i can't use startAt() and endAt() functions as well.
code snippet:
=> myList contains usernames. This code doesn't yield accurate results.
Any help would be really appreciated! Thank you!
FirebaseRecyclerOptions<MainModel> options =
new FirebaseRecyclerOptions.Builder<MainModel>()
.setQuery(FirebaseDatabase.getInstance().getReference().child("users").orderByChild("username")
.startAt(myList.get(0)).endAt(myList.get(myList.size()-1)),MainModel.class).build();
As already mentioned in the comment, the Firebase-UI library doesn't help in your case, because it doesn't allow you to pass multiple queries to the FirebaseRecyclerOptions object. So you need to perform a separate query and use the combined result.
When you are calling .get() on a Firebase Realtime Database query object, you are getting back a Task object. So the key to solving this problem is to use whenAllSuccess(Collection> tasks). In your case, it should look like this:
DatabaseReference db = FirebaseDatabase.getInstance().getReference();
DatabaseReference usersRef = db.child("users");
Query query = usersRef.orderByChild("username");
List<Task<DataSnapshot>> tasks = new ArrayList<>();
for (String username : myList) {
tasks.add(query.equalTo(username).get());
}
Tasks.whenAllSuccess(tasks).addOnSuccessListener(new OnSuccessListener<List<Object>>() {
#Override
public void onSuccess(List<Object> list) {
//Do what you need to do with your list.
for (Object object : list) {
MainModel mm = ((DataSnapshot) object).getValue(MainModel.class);
if(mm != null) {
Log.d("TAG", mm.getUsername());
}
}
}
});
Assuming that you have in your MainModel class a getter called getUsername(), the result in your logcat will be all the usernames of all returned children.
I am working on a student-teacher private messenger application using Firebase and I can insert data inside the root like this:
The usernames are retrived from a MySQL database, so I just only need to make a query. I would like to get only the data inside a ListView where chatID equals to my generated ID. I've searched in a lot of places like here but can't make the DatabaseReference working. Here is my code:
private void displayStudentChatMessages() {
listofMessages = (ListView) findViewById(R.id.list_msg);
adapter = new FirebaseListAdapter<BubbleMessageStudent>(this, BubbleMessageStudent.class, R.layout.item_chat_right, FirebaseDatabase.getInstance().getReference()) {
#Override
protected void populateView(View v, BubbleMessageStudent model, int position) {
TextView studentUsername = (TextView) v.findViewById(R.id.message_user_sender);
TextView studentMessage = (TextView) v.findViewById(R.id.message_user);
TextView studentSentDate = (TextView) v.findViewById(R.id.message_usertime);
studentUsername.setText(model.getStudentUsername());
studentMessage.setText(model.getStudentMessage());
studentSentDate.setText(android.text.format.DateFormat.format("yyyy-MM-dd%n(HH:mm:ss)", model.getStudentMessageTime()));
}
};
listofMessages.setAdapter(adapter);
listofMessages.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL);
}
As #cricket_007 commented, you'll need a query to get the chat messages with the correct ID:
rootRef = FirebaseDatabase.getInstance().getReference();
chatQuery = rootRef.orderByChild("chatID").equalTo("teststudent-testteacher...");
adapter = new FirebaseListAdapter<BubbleMessageStudent>(
this, BubbleMessageStudent.class, R.layout.item_chat_right, chatQuery)...
With this code your adapter will only show the messages with the correct chatID.
But in general your data model seems suboptimal. You've essentially mapped a table from your MySQL database into a node in Firebase. It probably works for now, but there are better ways to do this mapping.
In Firebase (and many other NoSQL databases) you should model your data for what you show on the screen. So if your app shows a chat room, which is a list of messages with the same chatID, then you should model precisely that in the database: a list of messages with the same chat ID:
chatId1
chat1Message1: ...
chat1Message2: ...
chat1Message3: ...
chatId2
chat2Message1: ...
chat2Message2: ...
chat2Message3: ...
With this structure you don't need a query to read the messages for a specific chat room. Instead you can directly access the node where they're under:
chatRoom = rootRef.child("teststudent-testteacher...");
adapter = new FirebaseListAdapter<BubbleMessageStudent>(
this, BubbleMessageStudent.class, R.layout.item_chat_right, chatRoom)...
This results in much better scalability.
I recommend reading NoSQL data modeling and watching Firebase for SQL developers.
I have the following Firebase database:
All i want to do, is to display all the lists that belong to a specific user. In this case, i want to display List aaa and List bbb that belong to gmail#gmail,com user. With this query:
databaseReference = FirebaseDatabase.getInstance().getReference();
Query query = databaseReference.child("Lists").orderByChild("ListName");
firebaseListAdapter = new FirebaseListAdapter<ListModel>(this, ListModel.class, android.R.layout.simple_list_item_1, query) {
#Override
protected void populateView(View v, ListModel slm, int position) {
((TextView)v.findViewById(android.R.id.text1)).setText(slm.getListName());
}
};
I achieve to display all the lists but i want to display only the lists that belong to a single user and has the value of true. How can i do that?
Thanks in advance!
There are two ways to achieve this behaviour.
Query query = DatabaseRef.getReference().child("Lists").orderByChild("Users").equals("gmail#gmail,com")
Then add the ChildEventListener to this reference
In Firebase data structure, make the email id parent and add all the childs under it, like
Lists
\gmail#gmail,com
\listName aaa
\listName bbb
You can get data from this structure from below reference:
Query query = DatabaseRef.getInstance().child("Lists").child("gmail#gmail,com")
Then add ChildEventListener listener with your ref object.
Hope this will work for you..
--- Edited ----
Try using this:
FirebaseDatabase firebaseDatabase = FirebaseDatabase.getInstance();
DatabaseReference ref = firebaseDatabase.getReference().child("Lists").orderByChild("Users").equalTo("gmail#gmail,com");
ref.addChildEventListener(New ChildEventListener......);
I'm currently using FirebaseRecyclerAdapter to retrieve data from a Firebase database, and I've pretty much worked out how to retrieve the data in the order I desire.
To avoid duplication and ease database maintenance, I'd like to add a key to a database entry that allows me to return queries based on that key. I was originally storing data twice. Once for all to see, and once if a user had joined a certain group (under groupName).
To return a query based on group, my original search was as follows:
databaseReference.child(groupName).child("exerciseId"+mExerciseId).orderByChild(sortOrder).limitToFirst(100);
but I believe duplication can be avoided by adding the key "group" to my post. (it also make maintenance much easier as users switch groups).
The "group" database query has now become:
databaseReference.child("exerciseId"+mExerciseId).orderByChild("group").equalTo(groupName);
All is good, except that the data is no longer sorted as per "sortOrder". As firebase does not allow multiple sort criteria, I believe my solution lies in offline sorting.
So, how does one sort the adapter offline?
My adapter is pretty standard:
mAdapter = new FirebaseRecyclerAdapter<Post, PostViewHolder>(Post.class, R.layout.item_post, PostViewHolder.class, dataQuery)
{
#Override
protected void populateViewHolder(final PostViewHolder viewHolder, final Post model, final int position)
{
final DatabaseReference postRef = getRef(position);
// Bind Post to ViewHolder, setting OnClickListener for the star button
viewHolder.bindToPost(model, position, postRef.getKey(), null);
}
mRecycler.setAdapter(mAdapter);
}
I've implemented Comparable in Post, the problem is where is the data stored so that I can pass it to Collections.sort() in this sort of way:
private List<Post> mPosts = new ArrayList<>();
mPosts.add(model);
Collections.sort(mPosts, Post.Comparators.ALLTIME);
The adapters in the FirebaseUI library currently always display data in the order that it is returned by the underlying FirebaseDatabase reference or Query.
You could file a feature request on the Github repo for it (since I'm not sure it is covered in this one yet). Alternatively you could fork the library and roll your own implementation of this functionality.
To feedback on the solution I came up with. I ended up populating my own List, which I can then sort or add to (if using multiple queries) depending on what I'm trying to achieve. This is then displayed using a standard RecyclerView adapter. It works great.
private final List<Post> postList = new ArrayList<>();
dataQuery.addListenerForSingleValueEvent(new ValueEventListener()
{
#Override
public void onDataChange(DataSnapshot dataSnapshot)
{
postList.clear(); // in this example it's a newQuery, so clear postList
for (DataSnapshot child : dataSnapshot.getChildren())
{
Post post = child.getValue(Post.class);
postList.add(post);
int myPosition = sortData(); // uses Collections.sort() to sort data
mAdapter.addPosts(postList);
mAdapter.notifyDataSetChanged();
mRecycler.scrollToPosition(myPosition);
}
}
});
I am new to Android and just started to understand some concepts like the RecyclerView. I am using Firebase as a database so I implemented the Firebase solution for that.
My Adapter:
FirebaseRecyclerAdapter<Offer,OfferViewHolder> adapter = new FirebaseRecyclerAdapter<Offer, OfferViewHolder>(
Offer.class,
R.layout.card_item,
OfferViewHolder.class,
mDatabaseReference.child("offer").getRef()
) {
#Override
protected void populateViewHolder(OfferViewHolder viewHolder, Offer model, int position) {
if(tvNoMovies.getVisibility()== View.VISIBLE){
tvNoMovies.setVisibility(View.GONE);
}
viewHolder.tvHeading.setText(model.getHeader());
viewHolder.tvStoreName.setText(model.getStoreName());
}
};
Now I have two questions:
Is it possible to filter results inside the adapter or do i have to use ChildEventListeners for that?
When referencing to a key that contains an Array or an object itself how to retrieve child values?
You can initialize the FirebaseRecyclerAdapter with either a DatabaseReference or a Query. As its name implies, the latter allows you to get a subset of the children at a specific location in the database.
For example say if you want to only show offers from a specific store:
DatabaseReference offers = mDatabaseReference.child("offer").getRef();
Query storeOffers = offers.orderByChild("storeName").equalTo("A. lazzi's store");
FirebaseRecyclerAdapter<Offer,OfferViewHolder> adapter = new FirebaseRecyclerAdapter<Offer, OfferViewHolder>(
Offer.class,
R.layout.card_item,
OfferViewHolder.class,
storeOffers
) {