I'm using a Firebase database to store and read a list of "clubs" in an Android app.
Below there's the Json representation of that.
{
"clubs" : [ {
"id" : 1,
"image" : {
"allocationByteCount" : 589824,
"byteCount" : 589824,
"config" : "ARGB_8888",
"density" : 320,
"generationId" : 212,
"height" : 384,
"mutable" : false,
"premultiplied" : true,
"recycled" : false,
"rowBytes" : 1536,
"width" : 384
},
"name" : "Axis"
}, {
"id" : 2,
"image" : {
"allocationByteCount" : 589824,
"byteCount" : 589824,
"config" : "ARGB_8888",
"density" : 320,
"generationId" : 214,
"height" : 384,
"mutable" : false,
"premultiplied" : true,
"recycled" : false,
"rowBytes" : 1536,
"width" : 384
},
"name" : "Allies"
}, {
"id" : 3,
"image" : {
"allocationByteCount" : 589824,
"byteCount" : 589824,
"config" : "ARGB_8888",
"density" : 320,
"generationId" : 216,
"height" : 384,
"mutable" : false,
"premultiplied" : true,
"recycled" : false,
"rowBytes" : 1536,
"width" : 384
},
"name" : "Neutrals"
} ]
}
I'm using a FirebaseAdapter class to call methods upon the Firebase database.
But it returns null when trying to get all clubs.
Bellow theres the method that calls it:
public List<BDClub> getClubs() {
list.clear();
database.getReference("clubs").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
System.out.println(dataSnapshot.getChildrenCount());
for(DataSnapshot array : dataSnapshot.getChildren()){
clubs = array.getValue(BDClub[].class);
for(BDClub c : clubs){
list.add(c);
}
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
return list;
}
Is there a way to retrieve a list of clubs?
Thanks in advance.
Looking at your Json representation i think clubs is child in main database reference so you can try the following:
FirebaseDatabase.getInstance().getReference().child("clubs").addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()){
System.out.println(dataSnapshot.getChildrenCount());
for(DataSnapshot array : dataSnapshot.getChildren()){
clubs = array.getValue(BDClub[].class);
for(BDClub c : clubs){
list.add(c);
}
}
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
Tip:
Do not return list like that from the function because these calls happen asynchronously so there is a huge chance that you will get empty list every time,Use listeners:
How to create our own Listener interface in android?
Related
I'm having trouble writing in my database because I have multiple unique ids that I don't know how to access.
I know that for writing I need to use something like this:
DatabaseReference ref=database.getReference().child("Children")
ChildData data = new ChildData(fullName,age);
ref.push().setValue(data);
My database looks like this:
{
"Children" : {
"55hxObZjRLY9PSZxZxGgSTRKzpc2" : {
"-MzUih5e40OsWPF_Dj0q" : {
"age" : "22",
"fullName" : "Cristina "
},
"plays" : {
"-MznnNih5fItYf2usXB4" : {
"centiseconds" : "70",
"currentDate" : "01.04.2022",
"currentHour" : "04:23:30",
"numberOfFails" : "5",
"seconds" : "2"
}
}
}
},
"Data" : {
"id1" : {
"centiseconds" : "70",
"currentDate" : "01.04.2022",
"currentHour" : "04:23:30",
"numberOfFails" : "5",
"seconds" : "2"
}
}
}
I need the "plays" child to be under "fullName" in "-MzUih5e40OsWPF_Dj0q", not as a separated child. How can I access the path without hardcoding it like this ref.child("MzUih5e40OsWPF_Dj0q").child("plays").push().setValue(data)? I will have multiple children in "Children" with different ids, I won't be able to harcode them.
Is there any function that returns the path for the unique id?
Here is the entire function:
public void writeNewData
(String fullName,String age) {
DatabaseReference reference = database.getReference().child("Data");
DatabaseReference ref=myRef.push();
ChildData data = new ChildData(fullName,age);
ref.push().setValue(data);
reference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot snapshot) {
for (DataSnapshot ds : snapshot.getChildren()) {
DatabaseReference playRef=ref.child("plays");
DatabaseData databaseData = ds.getValue(DatabaseData.class);
playRef.push().setValue(databaseData);
}
}
#Override
public void onCancelled(#NonNull DatabaseError error) {
}
});
}
Edit: This is my desired schema:
{
"Children" : {
"55hxObZjRLY9PSZxZxGgSTRKzpc2" : {
"-MzUih5e40OsWPF_Dj0q" : {
"age" : "22",
"fullName" : "Cristina ",
"plays" : {
"-MznnNih5fItYf2usXB4" : {
"centiseconds" : "70",
"currentDate" : "01.04.2022",
"currentHour" : "04:23:30",
"numberOfFails" : "5",
"seconds" : "2"
}
}
},
}
},
"Data" : {
"id1" : {
"centiseconds" : "70",
"currentDate" : "01.04.2022",
"currentHour" : "04:23:30",
"numberOfFails" : "5",
"seconds" : "2"
}
}
}
If you want the plays information to be a sibling of the age and fullName properties, then you will need to have a plays field/property in your ChildData class.
You'll need two classes, one to represent a "play" and one to represent a "child". At its minimum these will look like:
public class Play {
public String centiseconds, currentDate, currentHour, numberOfFails, seconds;
}
public class Child {
public String age, fullName;
public Map<String, Play> plays = new HashMap<>();
}
If you read/write this class, you will get plays nested under the child's data.
I am trying to retrieve data from the Firebase Realtime Database and I only want where the category is equal to a String. For example, if my string is football then I should get all the data that has the category football in it. I run my app with the code I am about to show you but I get nothing but a blank page. I don't know what I am doing wrong.
databaseReference = FirebaseDatabase.getInstance().getReference();
if (Categories.InternetConnection.checkConnection(Categories.this)) {
databaseReference.child("Sports").orderByChild("category").equalTo("football")).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
myUploads.clear();
for (DataSnapshot userSnapshot : dataSnapshot.getChildren()) {
for (DataSnapshot postsnapshot : userSnapshot.getChildren()) {
Model_Information upload = postsnapshot.getValue(Model_Information.class);
Collections.shuffle(myUploads);
myUploads.add(upload);
recyclerView.invalidate();
}
}
linearLayoutWithoutItems.setVisibility(View.GONE);
recyclerView.setVisibility(View.VISIBLE);
aAdapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(Categories.this, databaseError.getMessage(), Toast.LENGTH_LONG).show();
}
});
Firebase Json
{
"MyStudents" : {
"KihlyfLkJMQ5uZWBDgLWNuBHKAE2" : {
"-MSr8HG6QCR2sO8MZHoM" : {
"category" : "Football",
"created" : "2-19-2021",
"name" : "Benny",
"time" : "2:47 AM",
"timestamp" : 1613684875762
},
"-MSr8awtvzrmm3P6A2LB" : {
"category" : "Basketball",
"created" : "2-19-2021",
"name" : "patrick",
"time" : "2:49 AM",
"timestamp" : 1613684960454,
},
"-MSr8mSn5OSTu5vdT4Wt" : {
"category" : "Football",
"created" : "2-19-2021",
"name" : "Shawn",
"time" : "2:50 AM",
"timestamp" : 1613685007616,
}
{
"MyStudents" : {
"WahlyfLkJMQ5uZWBDgLWNuBHKAE2" : {
"-MSr8HG6QCR2sO8MZHoM" : {
"category" : "Football",
"created" : "2-19-2021",
"name" : "Len",
"time" : "2:47 AM",
"timestamp" : 1613684875762
},
"JJr8awtvzrmm3P6A2LB" : {
"category" : "Basketball",
"created" : "2-19-2021",
"name" : "Armstrong",
"time" : "2:49 AM",
"timestamp" : 1613684960454,
},
"-JJr8mSn5OSTu5vdT4Wt" : {
"category" : "Football",
"created" : "2-19-2021",
"name" : "Bill",
"time" : "2:50 AM",
"timestamp" : 1613685007616,
}
The problem in your code lies in the fact that you are using an incorrect query:
databaseReference.child("Sports").orderByChild("category").equalTo("football"))
Assuming that MyStudents is a child right under your root node and the following statement:
if (Categories.InternetConnection.checkConnection(Categories.this)) { /* ... */ }
Returns true, please use the following query:
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference uidRef = rootRef.child(uid);
Query queryByCategory = uidRef.orderByChild("category").equalTo("Football");
queryByCategory.addValueEventListener(/* ... */);
Things to notice:
KihlyfLkJMQ5uZWBDgLWNuBHKAE2 is the UID of the logged-in user and should be added as a child in the reference.
The value of the category property is called "Football" and not "football", with lower-case "f".
Edit:
According to your last comment:
I'm not trying to just get their information I'm trying to get everyone that has students whose category is Football
There is no way you can achieve that using your actual database structure. The most simple solution I can think of is to create a new node that contains all Model_Information objects, no matter the user is. This practice is called denormalization and is a common practice when it comes to Firebase. For a better understanding, I recommend you see this video, Denormalization is normal with the Firebase Database.
Also, when you are duplicating data, there is one thing that needs to keep in mind. In the same way, you are adding data, you need to maintain it. In other words, if you want to update/delete an item, you need to do it in every place that it exists.
Here is the answer. Hopefully its helpful for someone :)
databaseReference = FirebaseDatabase.getInstance().getReference().child("MyStudents");
if (Categories.InternetConnection.checkConnection(Categories.this)) {
databaseReference.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
myUploads.clear();
for (DataSnapshot userSnapshot : dataSnapshot.getChildren()) {
for (DataSnapshot postsnapshot : userSnapshot.getChildren()) {
Model_Information upload = postsnapshot.getValue(Model_Information.class);
Collections.shuffle(myUploads);
if (upload.getCategory().equals("Football")) {
myUploads.add(upload);
}else{
Toast.makeText(Categories.this, "No results", Toast.LENGTH_LONG).show();
}
recyclerView.invalidate();
}
myUploads.add(upload);
recyclerView.invalidate();
}
}
aAdapter.notifyDataSetChanged();
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
Toast.makeText(Categories.this, databaseError.getMessage(), Toast.LENGTH_LONG).show();
}
});
Im trying to order my database by child value "Month" but orderByChild is not working. It works when I use onChildEventListener instead of addListenerForSingleValueEvent But I dont wnat to use childEventListener
Here is my database
"Stats" : {
"2019" : {
"YxdZZHGy3rW4xdjORfk2i5mFRYG2" : {
"August" : {
"Weight" : {
"Body_Fat" : "29",
"Month" : 8,
"Weight" : "68"
}
},
"October" : {
"Weight" : {
"Body_Fat" : "29",
"Month" : 10,
"Weight" : "67"
}
},
"September" : {
"Weight" : {
"Body_Fat" : "28.5",
"Month" : 9,
"Weight" : "65.5"
}
}
}
}
},
And here is the java code
userStatsDatabase.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
Query query = userStatsDatabase.child(ds.getKey()).child("Weight").orderByChild("Month").limitToFirst(12);
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
if (dataSnapshot.exists()) {
Map<String, Object> map = (Map<String, Object>) dataSnapshot.getValue();
pastMonthsBodyFat = Float.parseFloat(map.get("Body_Fat").toString());
pastMonthsWeight = Float.parseFloat(map.get("Weight").toString());
pastWeightList.add(pastMonthsWeight);
pastBodyFatList.add(pastMonthsBodyFat);
Toast.makeText(Stats.this, map.get("Month").toString(), Toast.LENGTH_SHORT).show();
}
}
#Override
public void onCancelled(#NonNull DatabaseError databaseError) {
}
});
}
The Toast should print month values in order 8,9,10 but it is printing the values 8,10,9
If userStatsDatabase points to this JSON (for a specific user):
{
"August" : {
"Weight" : {
"Body_Fat" : "29",
"Month" : 8,
"Weight" : "68"
}
},
"October" : {
"Weight" : {
"Body_Fat" : "29",
"Month" : 10,
"Weight" : "67"
}
},
"September" : {
"Weight" : {
"Body_Fat" : "28.5",
"Month" : 9,
"Weight" : "65.5"
}
}
}
Then you can get the results in order of Month with:
Query query = userStatsDatabase..orderByChild("Weight/Month");
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(#NonNull DataSnapshot dataSnapshot) {
for (DataSnapshot monthSnapshot: dataSnapshot.getChildren()) {
System.out.println(monthSnapshot.getKey()); // August, September, October
System.out.println(monthSnapshot.child("Weight/Month").getValue(Long.class)); // 8, 9, 10
}
}
...
I gave up using Firebase queries to sort the data , Im sure there is nothing wrong with my code,anyways I decided to sort it "after" adding the data to the arrayList using Collections.sort and it worked. Thanks
P.S if someone knows why my firebase query didnt work I would still like to know the reason :S
Here is the code in case someone else needs to sort data from an arrayList
//sort the item to show months in ascending order
Collections.sort(items, new Comparator<PastMonthsWeightStats>(){
#Override
public int compare(PastMonthsWeightStats obj1, PastMonthsWeightStats obj2) {
// ## Ascending order
// return obj1.firstName.compareToIgnoreCase(obj2.firstName); // To compare string values
//return Float.valueOf(obj1.getMonthNumber()).compareTo(Float.valueOf(obj2.getMonthNumber())); // To compare integer values
// ## Descending order
// return obj2.firstName.compareToIgnoreCase(obj1.firstName); // To compare string values
return Integer.valueOf(obj2.getMonthNumber()).compareTo(Integer.valueOf(obj1.getMonthNumber())); // To compare integer values
}
});
"Subscription" : {
"1519197182611" : {
"address" : "Mumbai",
"dateTime" : "Feb 21, 2018 12:42:57 PM",
"name" : "ABC",
"phone" : "1264897809",
"uIdpId" : "123456"
},
"1519197186551" : {
"address" : "Mumbai",
"dateTime" : "Feb 21, 2018 12:42:57 PM",
"name" : "DCF",
"phone" : "1264897809",
"uIdpId" : "7897"
},
"1519197360198" : {
"address" : "Mumbai",
"dateTime" : "Feb 21, 2018 12:45:54 PM",
"name" : "XYZ",
"phone" : "1264897809",
"uIdpId" : "45656"
}
}
I want to delete the node through whose name is ABC.
So how can i proceed further. I got stuck here.
Try this:
DatabaseReference data = FirebaseDatabase.getInstance().getReference().child("Subscription");
data.orderByChild("name").equalTo(ABC).addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot data: dataSnapshot.getChildren()){
data.getRef().removeValue();
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
The snapshot is at child Subscription, then you use orderByChild("name").equalTo(valuehere) which is the condition that name should be equal to ABC for example.
Then using the for loop you iterate inside the random pushids, getRef() will give you the reference of this source location and removeValue() will remove the node.
Fetch messages method
private void fetchMessages() {
rootRef.child("Messages").child(MessageSenderId).child(MessageRecieverId)
.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
Messages messages = dataSnapshot.getValue(Messages.class);
messagesList.add(messages);
messageAdapter.notifyDataSetChanged();
}
#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) {
throw databaseError.toException();
}
});
}
Defining Ids
MessageSenderId = mAuth.getCurrentUser().getPhoneNumber();
MessageRecieverId = getIntent().getStringExtra("visit_user_id");
trying to make a basic chat app
Since only the senders id is called in rootref only the messages i send r being displayed in d recyclerview... im unable to receive messages because of this... how can i make it to retrieve recievers id and senders id also at the same time
Database strucutre
{
"Messages" : {
"+918105571584" : {
"+919945342730" : {
"-L58IPCLEeE21vH_-1Ry" : {
"message" : "Hi",
"seen" : false,
"time" : 1518427022478,
"type" : "text"
},
"-L58IU1VIHN0rHaUox3a" : {
"message" : "Hello",
"seen" : false,
"time" : 1518427042257,
"type" : "text"
},
"-L58IYN1GpHPdkWCY7Hn" : {
"message" : "Hi",
"seen" : false,
"time" : 1518427060021,
"type" : "text"
}
}
},
"+919945342730" : {
"+918105571584" : {
"-L58IPCLEeE21vH_-1Ry" : {
"message" : "Hi",
"seen" : false,
"time" : 1518427022478,
"type" : "text"
},
"-L58IU1VIHN0rHaUox3a" : {
"message" : "Hello",
"seen" : false,
"time" : 1518427042257,
"type" : "text"
},
"-L58IYN1GpHPdkWCY7Hn" : {
"message" : "Hi",
"seen" : false,
"time" : 1518427060021,
"type" : "text"
}
}
}
},
"Users" : {
"+918105571584" : {
"Email" : "",
"Name" : "Akash",
"Quote" : "",
"Status" : ""
},
"+919945342730" : {
"Email" : "",
"Name" : "Sav",
"Quote" : "",
"Status" : ""
}
}
}
According to your last comment, I understand that you can display only the messages that correpond to a single user. A user can see only his messages butd not other user messages. To solve this, you need to create chat rooms, in which every user can add messages that can be seen by all chat room members.
So for that, you need to change your database structure. You cannot achieve this, using the actual database.