Android - Retrieving data from Firebase - android

I am developing an android application where older kids can pick up younger kids and walk to school. With the application the authenticated (email and password) younger kid can choose between three adresses to get picked up. As of right now my realtime database looks like this:
I want to retrieve the different addresses and the users who picked the addresses. I am thinking I have to use recyclerview to get the data, but I am unsure on if it is possible to do with my database structure.

Using the FirebaseUI database package makes it simple to bind data from the Firebase Realtime Database to your app's UI. Specifically using FirebaseUI with indexed data is applicable for your current database structure.
For example, you'd use something similar to:
// keyQuery - the Firebase location containing the list of keys to be found in dataRef
// dataRef - the Firebase location to watch for data changes. Each key found at
// keyRef's location represents a list item.
Query keyQuery = FirebaseDatabase.getInstance().getReference("/Addresses/Street 10/users");
DatabaseReference dataRef = FirebaseDatabase.getInstance().getReference("/User");
FirebaseRecyclerOptions<User> options = new FirebaseRecyclerOptions.Builder<User>()
.setIndexedQuery(keyQuery, dataRef, User.class)
.build();
Where your User class is:
public class User {
private String username;
public User() {}
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
// ...
}
You can then use the above created options variable to create a FirebaseRecyclerAdapter instance and then call startListening() on it*.
Using FirebaseUI in this way will automatically handle matching the keys under /Addresses/Street 10/users to the /User node.
* Version 2.x of FirebaseUI uses FirebaseIndexRecyclerAdapter instead and starts listening automatically so doesn't require a startListening() call. The above example is applicable for version 3.0, see FirebaseUI 3.0 upgrade guide.

Following on from my previous answer, this one should accommodate your requirement to create a list of all addresses and their associated users, which may be closer to what you're looking for.
Again you can use the FirebaseUI database package to simplify the RecyclerView creation.
You'll need to start denormalizing your data, so your data structure should also include usernames in the addresses node:
{
"Addresses" : {
"Street 10" : {
"name" : "Street 10",
"users" : {
"VAzdMWafK6cyhmJnOI4br5xiQg93" : "John"
}
}
},
"User" : {
"VAzdMWafK6cyhmJnOI4br5xiQg93" : {
"username" : "John",
"address" : "Street 10"
}
}
}
Note: you only need to add user IDs to their chosen address (and remove the node if they change selection), so don't use "VAzdMWafK6cyhmJnOI4br5xiQg93" : false for addresses the user has not selected as this could cause confusion.
Then you can use:
Query query = FirebaseDatabase.getInstance().getReference("/Addresses");
FirebaseRecyclerOptions<Address> options = new FirebaseRecyclerOptions.Builder<Address>()
.setQuery(query, Address.class)
.build();
Where Address is something like:
public class Address {
private String name;
private Map<String, String> users;
public Address() {}
public Map<String, String> getUsers() {
return this.users;
}
// ...
}
And create a FirebaseRecyclerAdapter instance from the options variable. Then when binding the viewholder in the adapter, you can access the users map to list each user that has selected this address, without the need to load the entire User object unnecessarily.
This pattern is called denormalization and is the suggested approach when using NoSQL databases (like Firebase Realtime Database). The main downside to this is data duplication: so for example, when a user changes their selected address, you'll need to change:
The address value under the user, and
the users list under the address.
Likewise, if a user is allowed to change their username, you'll need to update the username under their chosen address as well as in the user's node.
For details on dealing with this, see this answer which explains a number of methods (although the examples are in JavaScript, the premise still applies).

Related

fetch the data from firebase and populate the recyclerview through for loop if the keys of the node are stored locally [duplicate]

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.

Firebase Update Multiple Child value From Multiple Key for Specific Child Value

I have below firebase database Structure.I am saving mobile no as child name. What I need to do is first get the tBid value for each key having specific mobile no value equal to ok then add/deduct a number and then update tBid value for all key under b_ookk_node
I have tried below code so far but it is not working.How can I achieve this
final String mobile_no = singleToneClass.getInstance().getData();
mDatabasebook = FirebaseDatabase.getInstance().getReference().child("b_ookk_node");
Query ref_book = mDatabase.child(mobile_no).equalTo("ok");
ref_book.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.hasChildren()) {
for (DataSnapshot datas: dataSnapshot.getChildren()) {
final int total_bid = Integer.parseInt(datas.child("tBid").getValue(String.class));
String t_bid = Integer.toString(total_bid - 1);
mDatabasebook.child("tBid").setValue(t_bid);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Assuming that b_ookk_node in your code matches the struck out node in your JSON screenshot, this code looks OK. But it'd require you to define an index for each mobile number, since an index can only be defined on a property of which you specify the name. Since I assume the phone numbers are user-entered data, defining an index for each of them isn't feasible
In short: your current data structure allows your to easily look up the mobile number of a push ID, but not the push ID for a mobile number. To allow the latter you'll need to set up an additional data structure, which looks like this:
"number_to_pushid_map": {
"096554885": {
"-LyON1kEn...sWpW": true
"-LyON1kEn...key2": true
}
}
In this structure you can then look up the push ID for a number that the user entered.
Also see:
Firebase query if child of child contains a value
Aside from that:
The if (dataSnapshot.hasChildren()) { in your code is not needed. If there are no child nodes, then dataSnapshot.getChildren() will already return an empty iterator, and the loop will never be entered.
Consider using a transaction for the updating of the bid, as right now two users updating the bid around the same time may end up overwriting each other's result.
Consider storing the tBid value as a number, instead of as a string, so that you don't have to constantly convert it back and forth.

how to check if a collection contains certain sub collection or not in firestore

i want to make this type of collection in my firestore
where chatRooms will be my collection name, combination of myUid and opponentsUid will be my sub-collection in which different documents will be placed. My problem is i want to check if my collection contains sub-collection named myUid_opponentsUid or opponentsUid_myUid and i am not able to search a best query for doing this.
All i know is that we can fetch the whole list and then check if it contains the specific room or not, but its a lengthy process, so i want to better method for it.
Thanks in advance.
There are a few misconceptions in your question to clear up first:
In Firestore collections don't really exist as distinct entities. It's the documents inside a collection that cause it to become visible.
Also, collections can only contain documents, which in turn can contain collections, but the structure must alternate, so you can't have a collection called chatRooms that contains a collection myUid_opponentUid. Inside chatRooms there must be a document.
So if chat rooms contain messages, a straightforward way to do what you want is to create a document that represents that chatRoom. Then within that create a subcollection for the messages.
If you sort the UIDs before creating the composite chatRoom key you can then test whether or not the chat room exists by using a single get(). The structure would look like this:
chatRooms/(uid-pair)/messages/(message-id)
Note that you don't actually need to store anything at the chatRoom/(uid-pair) level to create children at the messages level: you can just create new messages and listen directly.
Try to Read Total Number of child .! Hope this thing may helps you.and if you want to implement your own api then try using Firebase Functions..and last thing I want to add is that if You want to add get Count without reading number of child you have to implement one method that getChildCount before storing data and then append them with key like JiGh_31GA20JabpZBfa,1` and only read keys and then use comma separator and you will get your result that this parent contains child or not.?
DatabaseReference myRef = database.getReference();
//You can use the single or the value.. depending if you want to keep track
String id= UUID.randomUUID().toString();//randomID for task
Object object=new Object ();
public int chidcount(String child){
string childcount="0";
//You can use the single or the value.. depending if you want to keep track
myRef.child(child).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot snap: dataSnapshot.getChildren()) {
childcount=snap.getChildrenCount();
Log.e(snap.getKey(),snap.getChildrenCount() + "");
}
addvalue(childcount);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
private addvalue(String childcount){
object=setid(id);
object=setname("name");
getchildCount("object");
mdatabaseRef.child("rating").child(manager.getId()+childcount).child(currentEmployee.getId()).child(id).setValue(rating);}
I know I am late.
Posting for future users.
Try this:
DocumentReference datab = db.collection("collection_name").document("Doc_name");
datab.get().addOnSuccessListener(new OnSuccessListener<DocumentSnapshot>() {
#Override
public void onSuccess(DocumentSnapshot documentSnapshot) {
if(documentSnapshot.contains("field_name"))
{
Toast.makeText(YourActivity.this, "Child exixts.", Toast.LENGTH_SHORT).show();
}
else
Toast.makeText(YourActivity.this, "Doesnt exits.", Toast.LENGTH_SHORT).show();
}
});
For Firebase Firestore to check whether the document has entries (fields), Use this command
firebaseFirestore.collection("Users").document(userId)
.addSnapshotListener {
documentSnapshot, _ ->
if (documentSnapshot!!.contains("name")) {
Log.i("Name", "Name exists")
} else {
Log.i("Name", "Name doesn't exists")
}
}

FireBase Android Need 1 value saved under a single user

I have the following data structure on firebase for the user MF0qeRA4p7djfjgXxqwFOck3m6p02. I want to get the value of item3 to populate a single field into the User interface on an Android App. I have been looking through samples on Stackoverflow, but all I have found are outdated and do not work with the current version of firebase. I'm new to firebase completely and this is my first app on android. I've got the oncreate user method to populate the users email address and add the 4 item fields, but retrieving the data I'm completely lost and I am not sure where to even begin.
-Users
---MF0qeRA4p7djfjgXxqwFOck3m6p02
------item1:"1"
------item2:"2"
------item3:"3"
------item4:"4"
According to what I can identify is, you are facing problem retrieving data from this reference. Here is the code:
final DatabaseReference databaseReference = FirebaseDatabase.getInstance().getReference("Users");
databaseReference.child("MF0qeRA4p7djfjgXxqwFOck3m6p02").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Map<String, Object> map=(Map<String, Object>)dataSnapshot.getValue();
String item3=(String)map.get("item3");
display(item3);
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
Hope this helps.
You can create a custom model and inside you can insert elements. Something like this:
public class Item {
private List<Object> ojects;
}
There you can save instance of Item on database. In this case you have more controll. Other case is to use push() method, that will generate a new encoded key, something like this:
mDatabase.child("items").push().put(new Object());

How do I utilize filters and child elements in Google Firebase Database

Working on an Android app that is using the new Firebase Database framework. It has data objects that are modeled like this:
Where the Top parent (1234-4321) is the 'chat room', the data object are the 'chat messages', and the numbered items (0, 1, 2) are the 'individual message'.
I am able to get the entire Database without any trouble and read it via listeners:
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference myRef = database.getReference();
myRef.addChildEventListener(this);
myRef.addValueEventListener(this);
And I am able to get a single child in this fashion:
FirebaseDatabase database = FirebaseDatabase.getInstance();
String id = "1234-4321";
DatabaseReference myRef = database.getReference().child(id);
myRef.addChildEventListener(this);
myRef.addValueEventListener(this);
But I cannot for the life of me figure out how to get multiple objects of the same type. What I mean is, a user will be able to get More than one chat room (IE, both '1234-4321' and '1234-4432'), but the only way I can see to do this is either to:
1) loop through the onChildAdded or onDataChange listeners, separate out the items by matching the String ids, and updating them. This is, however, extremely inefficient as I am parsing the entire Database, which could be quite large
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
if(dataSnapshot != null){
try {
ChatObjectV2 objectV2 = (ChatObjectV2) dataSnapshot.getValue();
//Check here for ids and loop through everything
} catch (Exception e){
e.printStackTrace();
}
}
}
or
2) To add a specific child, but if I try to add more children it is going 'deeper' into the nested object when I want it to go 'wider'.
//This won't work because it is going 'deeper' instead of 'wider'
String id = "1234-4321";
String id2 = "1234-4432";
Query myQuery = myRef.child(id).child(id2);
And then loop through in the listener the same way, but, I would need to create a different DatabaseReference for every chat room, which is horribly inefficient.
It looks like the solution is probably to use filters, but I cannot for the life of me figure out how to utilize them in the existing FirebaseDatabase and DatabaseReference objects. Does anyone have any idea how to make a filter work with regards to the data schema / model I have listed here?
Thanks for the help!
I would try to explain you the basic use of filtering in these examples:
//getting first two chat rooms
Query chatRoomsQuery = databaseReference.limitToLast(2);
//getting last two chat rooms
Query chatRoomsQuery = databaseReference.limitToFirst(2)
//getting all active id
Query chatRoomsQuery = databaseReference.orderByChild("active").equalTo(true);
This is just a basic sample I would encourage you to go through this blog. Which explains advanced queries amazingly.
Alternatively, you can also go through these docs. They are different than what you shared.
Do let me know if this is what you were looking for.

Categories

Resources