I am having some issues with the Android version of my app. I completed the iOS version and am working on the Android data part. After I get the the snapshot in Swift, I can simply say something like this:
myList.addObject((snapshot.value["num"] as? String)!)
Then I have a nice list of of the numbers I need.
So far with Android it isn't that simple. Here is my how my data is structured and what I am looking for.
staffNUM
--staff
--12345677
-- num:112234
--2345689
-- num:090909
--44445677
-- num:999234
--6665689
-- num:888673
I can't change the way the data is created since the app for iOS is already being used.
Here is the question:
I have a reference to my database, which works.
mDatabase = FirebaseDatabase.getInstance().getReference();
Here is how I am calling the database after:
mDatabase.child("staffNUM/staff").addListenerForSingleValueEvent(
new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.getValue() != null) {
Log.d("Snap", "" + dataSnapshot.getValue());
StaffNum staffNum = dataSnapshot.getValue(StaffNum.class);
} else {
// something else happens
}
My results in the snapshot are:
D/Snap: {staff={12345677={num=112234},{2345689 ={num= 090909},{2345689 ={num= 090909}, {44445677={num= 999234}, {6665689 ={num= 888673}}
What is the best way to parse that data? I just need a list like I did in Swift to use in the app.
Edit:
Here is the class I added
#IgnoreExtraProperties
public class StaffNum {
public String num
public StaffNUM() {}
public StaffNUM(String num) {
this.num = num;
}
#Exclude
public Map<String, Object> toMap() {
HashMap<String, Object> result = new HashMap<>();
result.put("num", num);
return results;
}
}
If I call Log.d("num: ","" + staffNUM.num);
I still get
D/num:: null
Create a Staff POJO with the fields that you need from your Firebase structure
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for(DataSnapshot d : dataSnapshot.getChildren()) {
Staff staff = d.getValue(Staff.class);
Log.d("Snap", "num: " + staff.getNum());
}
}
Related
I'm trying to develop a simple application to learn firebase database.
Here is my realtime database schema
mydirectory
-contact_list
-LOyDhepB_IZlM6lZtko
mobileNumber: "9385746982"
name: "Jay"
-LOyDhetiPHalLhXrOaU
mobileNumber: "8000478912"
name: "Ravi"
-LOyDhetiPHalLhXrOaV
mobileNumber: "123456789"
name: "ABC"
-LOyDheubruATyyBp8dG
mobileNumber: "023456879"
name: "XYZ"
I want to get the list of data ordered by name
So I'm using this snippet to load the data in my android application
DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference();
mDatabase.child("contact_list").orderByChild("name").addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
Map<String, Object> objectMap = (HashMap<String, Object>) dataSnapshot.getValue();
Master.personList.clear();
for (Object obj : objectMap.values()) {
if (obj instanceof Map) {
Map<String, Object> mapObj = (Map<String, Object>) obj;
String name = (String) mapObj.get("name");
String mobileNumber = (String) mapObj.get("mobileNumber");
Person person = new Person(name, mobileNumber);
Master.personList.add(person);
populateListView();
}
}
}
#Override
public void onCancelled(DatabaseError error) {
// Failed to read value
Log.w("ANDs", "Failed to read value.", error.toException());
}
});
But it does not sort data based on the alphabetical order of name
key. Am I doing anything wrong or missing something?
P.S.
I've also indexing rules (ref), but still result is same! It doesn't sort data alphabetical wise.
{
"rules": {
"mydirectory": {
"contact_list": {
"$user_id": {
".indexOn": ["name"]
}
}
},
".read": true,
".write": true
}
}
I've tried many things from other posts like this topic but nothing works! Please don't make it duplicate instead please help me to solve it!
A HashMap can only contain a key and a value. And the keys in a Map are by definition not ordered. So when you call dataSnapshot.getValue(), you're throwing away all ordering information.
To maintain the order, you'll need to loop over dataSnapshot.getChildren():
public void onDataChange(DataSnapshot dataSnapshot) {
Master.personList.clear();
for (DataSnapshot contactSnapshot: dataSnapshot.getChildren()) {
String name = contactSnapshot.child("name").getValue(String.class);
String mobileNumber = contactSnapshot.child("mobileNumber").getValue(String.class);
Person person = new Person(name, mobileNumber);
Master.personList.add(person);
}
populateListView();
}
You'll also notice that I use child(...) to get a child snapshot for a specific property and get the String value from it. Your approach for that would work too, but I find that I get better error messages when I stick to a snapshot longer (instead of converting to a Map).
Looked at many solutions and can't seem to find one in order to retrieve nodes as an Array
mDatabase = FirebaseDatabase.getInstance().getReference("users");
mDatabase.child("users").child(auth.getUid());
mDatabase.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
GenericTypeIndicator<List<String>> t = new GenericTypeIndicator<List<String>>() {};
List<String> yourStringArray = dataSnapshot.getValue(t);
Log.w(TAG, "users array: " + yourStringArray);
}
In android studio I get this error on t:
Cannot resolve method'getValue(com.firebase.client.GenericTypeIndicator<java.util.List<java.lang.String>>)'
My database structure: https://gyazo.com/9f2109d3d5c699329b74d6a6ed8279e8
Alternative solution to return using getValue but cannot convert to array or list...
mDatabase = FirebaseDatabase.getInstance().getReference("users");
mDatabase.child("users").child(auth.getUid());
mDatabase.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
collectData((Map<String, Object>) dataSnapshot.getValue());
Log.w(TAG, "users array: " + dataSnapshot.getValue());
}
public String collectData(Map<String, Object> value) {
for (Map.Entry<String, Object> entry : value.entrySet()) {
users.add((Map.Entry) entry);
}
return users.toString();
}
but I really need it as an array as a hashmap is not suitable for my purposes
You're mixing up versions of the Firebase client library SDKs. You can tell by seeing this in the error message:
com.firebase.client.GenericTypeIndicator
com.firebase comes from an obsolete version. You want the ones from com.google.firebase. Remove the legacy SDK from your build.gradle and us only the new ones.
String userID = selectedCharacter.getUserID();
String charID = selectedCharacter.getCharID();
Character editedCharacter = new Character(userID, charID, name, hitPoints, armorClass, level, experience, gold);
databaseRef
.orderByChild("charID")
.equalTo(selectedCharacter.getCharID())
.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
// Translate the character to a map of its data
Map<String,Object> updates = editedCharacter.toMap();
// Update ONLY the node with charID = editedCharacter.getCharID()
databaseRef.updateChildren(updates);
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException();
}
});
So I'm trying to update a character's stats in my firebase database. As you can see:
here
the code I'm using is actually putting the update in character's root instead. What am I doing wrong here? I'm unsure of how to find the node with the key as I'm not storing the key anywhere.
When you execute a query against the Firebase Database, there will potentially be multiple results. So the snapshot contains a list of those results. Even if there is only a single result, the snapshot will contain a list of one result.
So your code will need to handle the fact that the snapshot is a list. In the case of Android that means that you loop over snapshot.getChildren():
databaseRef
.orderByChild("charID")
.equalTo(selectedCharacter.getCharID())
.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot child: dataSnapshot.getChildren()) {
// Translate the character to a map of its data
Map<String,Object> updates = editedCharacter.toMap();
// Update ONLY the node with charID = editedCharacter.getCharID()
child.getRef().updateChildren(updates);
}
}
Instead of databaseRef.updateChildren(updates);
Could you try
databaseRef.child(dataSnapshot.getKey()).setValue(updates)
Then see if it works.
I'm running into a weird issues in which a Firebase query using orderByChild() doesn't actually order the data. Below is a snapshot of the data that I'm trying to order: (total is off for the sake of this example)
This is the code that I've used so far:
Query query = locationComment.orderByKey();
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.getValue() == null) {
return;
}
data.clear();
adapter.notifyDataSetChanged();
String userId;
String time;
String comment;
Map<String, String> commentMap = (Map) dataSnapshot.getValue();
for (Map.Entry<String, String> entry : commentMap.entrySet()) {
if(!((entry.getKey()).contains("total"))) {
String[] keyString = (entry.getKey()).split(",");
time = keyString[0];
userId = keyString[1];
comment = entry.getValue();
Date resultdate = new Date(Integer.parseInt(time));
data.add(new Comment(comment,
DateFormat.getDateTimeInstance().format(resultdate), userId));
adapter.notifyItemInserted(data.size());
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
I'm getting each and every key-value pair (barring total) except that it's not in order as expected (ordered by key). The Firebase docs say that the keys are ordered lexicographically if they can't be parsed into a 32 bit integer.
Either way though the order should be as shown in the image but the data that I get back while looping through the map is not in this order.
I would really appreciate it if someone could point me in the right direction. Thanks!
When you execute a query you get three things:
they keys
the values
the relative order between these
When you convert the result to a Map it can only hold two of these, so the order is lost. To prevent this, you should use the DataSnapshot.getChildren() method:
Query query = locationComment.orderByKey();
query.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
if (dataSnapshot.getValue() == null) {
return;
}
data.clear();
for (DataSnapshot child : dataSnapshot.getChildren()) {
...
}
adapter.notifyDataSetChanged();
}
Also see this example in the Firebase documentation on working with lists: https://firebase.google.com/docs/database/android/lists-of-data#listen_for_value_events
Looks like your data is badly structured.
Firebase has it's internal way of keying, and Firebase only can order those keys, with additional criteria if wanted. But since your key, is a custom key, firebase can't and won't order this branch.
The solution is to restructure your data in a meaningful way, like this
+ comments
+ total: 13
+ data:
+ 12uoasjihdou3
+ time: xx
+ userID: xx
+ comment: xx
+ 123tjiueoi134
+ 1piahf9hasheui
+ 6890324890oiuwer
Always use push() to generate new keys, do not create custom keys for lists, thats a total no go
FirebaseDatabase.getReference("comments").child("data").push({yourdata});
if you want to order your data, this is how you do that
FirebaseDatabase.getReference("comments").child("data").orderByChild("time");
I have data structure as:
https://law-apps-44h221543638e.firebaseio.com/apps to promote/0/ >> name:"First App", package:"fra"
https://law-apps-44h221543638e.firebaseio.com/apps to promote/1/ >> name:"Second App", package:"sca"
https://law-apps-44h221543638e.firebaseio.com/apps to promote/2/ >> name:"Third App", package:"tha"
and I query it using
Firebase myFirebaseReference = new Firebase("https://law-apps-44h221543638e.firebaseio.com/apps to promote");
Query queryRef = myFirebaseReference.orderByChild("name");
queryRef.addListenerForSingleValueEvent(new ValueEventListener() { // override methods })
But it returns the data in the same order i.e sorted by the first child (1,2,3, etc.)
How should I query it so it sorts the data by the "name" tag of each child?
Ok so I found the answer to this question and I am writing it so others may benefit from it. I was using an older technique wherein I was finding from datasnapshot my apps using their parents' numbers and due to this, I was delibrately undoing the ordering.
Now I have used dataSnapshot.getChildren().iterator() and it is now working correctly. Here's the code:
Query queryRef = myFirebaseReference.orderByChild("name");
queryRef.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
String name;
String my_package;
long lengthOfForLoop = dataSnapshot.getChildrenCount();
Iterator<DataSnapshot> child = dataSnapshot.getChildren().iterator();
for (int i = 0; i < lengthOfForLoop; i++) {
DataSnapshot next = child.next();
name = next.child("name").getValue(String.class);
my_package = next.child("package").getValue(String.class);
// do something with this data.
}
}
});
}
thanks, Usman!
I used the same code with the children iterable collection in a for loop.
This code was worked for me (in Kotlin):
accountsReference.child(accountId).child("actions").orderByChild("actionPosition").addListenerForSingleValueEvent( object : ValueEventListener {
override fun onDataChange(var1: DataSnapshot) {
if (var1.children != null) {
for (actionsEntries in var1.children) {
...
}
}