How to get array data on Firebase? - android

I have this Firebase:
I'm trying to get all the questions data with this code:
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference questionsRef = database.getReference("questions");
questionsRef.addChildEventListener(new ChildEventListener() {
#Override
public void onChildAdded(DataSnapshot dataSnapshot, String s) {
HashMap question = dataSnapshot.getValue(HashMap.class);
System.out.println(question.get("0"));
}
}
But I get the error:
com.google.firebase.database.DatabaseException: Class
java.util.HashMap has generic type parameters, please use
GenericTypeIndicator instead
I tried few ways but this is last error. How I can get each question data and all the options of the questions?

Options looks like a numbered list to me, so don't have to use a Map to get it's contents.
GenericTypeIndicator<List<String>> gti = new GenericTypeIndicator<List<String>>() {};
String question = dataSnapshot.child("question").getValue(String.class);
List<String> questionOptions = dataSnapshot.child("options").getValue(gti);

Map<String, String> question = dataSnapshot.child("options").getValue(Map.class);
Take Array of this question..

First, you should change question type to Map, not HashMap (like #varjo mentioned)
Second, in your code you get the value is 1 step above where it should be. So it should be like this:
Map<String, String> question = dataSnapshot.child("options").getValue(Map.class);
Hope this helps
EDIT
To get question text, use this:
String questionText = dataSnapshot.child("question").getValue(String.class);
Note: for best practice, I think you should create a custom object
that combine the question and options together

"options" is not a map, it is a list or an array. Do something like this
GenericTypeIndicator<List<String>> genericTypeIndicator = new GenericTypeIndicator<List<String>>() {};
List<String> list = dataSnapshot.child("options").getValue(genericTypeIndicator);

Related

populating recyclerview from nested table Firebase database

I have this structure in my Database inside the UserID I have this random ID which I declared when adding data to database I don't know how to call that to display the info inside to recycler view. Actually I can display the info in Recyclerview if the declared pushid is not there but I need that push ID to work on other modules. I am still learning so I get easily confused with this kind of thing. Any help would be so much appreciated.
This is the line which is calling the table.
mToolsDatabase = FirebaseDatabase.getInstance().getReference().child("toolHistory");
mToolsDatabase.child(list_user_id).child(mCurrentUser.getUid()).addValueEventListener(new ValueEventListener(){
public void onDataChange(DataSnapshot dataSnapshot) {
final String toolName = dataSnapshot.child("name").getValue().toString();
final String toolUser = dataSnapshot.child("user").getValue().toString();
final String toolBorrow = dataSnapshot.child("dateTimeBorrowed").getValue().toString();
final String toolReturn = dataSnapshot.child("dateTimeReturn").getValue().toString();
final String toolStatus = dataSnapshot.child("status").getValue().toString();
final String toolId = dataSnapshot.child("logId").getValue().toString();
viewHolder.setName(toolName);
viewHolder.setUser(toolUser);
viewHolder.setDateTimeBorrowed(toolBorrow);
viewHolder.setDateTimeReturn(toolReturn);
viewHolder.setStatus(toolStatus);
viewHolder.setLogId(toolId);
}
Firebase has its inbuilt method FirebaseRecyclerAdapter for display items in RecyclerView
Also, you can follow this link for more info
https://grokonez.com/android/firebase-realtime-database-display-list-of-data-firebaserecycleradapter-android-development

Saving data in Firebase using delimiter in Android

I am trying to save data in my firebase such that it appear like this:
I know that the way to input it manually in firebase is ["marie", "femmehacks"]
But how to I input it from android using delimiter..Note that I need to use Java 7 and String.join is not the solution in android.
Here are my codes:
StringBuilder newstring = new StringBuilder();
for (String movie: movies){
newstring.append(movie);
newstring.append(",");
}
String all = newstring.toString();
all = all.substring(0, all.length() - ",".length());
The output as per this code is now:
["marie,femmehacks"]
but I want it to appear like
["marie", "femmehacks"]
such that it is saved in firebase as per the image above. Any help?
Use this function TextUtils.join(CharSequence delimiter, Iterable tokens).
I got this from here https://developer.android.com/reference/android/text/TextUtils#join(java.lang.CharSequence,%20java.lang.Iterable)
android.text.TextUtils
public static String join(#NonNull CharSequence delimiter,
#NonNull Iterable tokens)
External annotations available:
Parameter delimiter: #android.support.annotation.NonNull
Parameter tokens: #android.support.annotation.NonNull
You may try like this. its works for me.
List<String> stringList = new ArrayList<>();
private String membersName = "";
for (UserInfo userInfo : userInfoList) {
stringList.add(userInfo.getUsername());
}
membersName = TextUtils.join(", ", stringList);
you can save like :
FirebaseDatabase.getInstance().getReference().child(“ChildName”).setValue(membersName);
You should push data as ArrayList<String>
ArrayList<String> movies = <enter code to get list>
FirebaseDatabase.getInstance().getReference().child(“yourChild”).setValue(movies);

Firebase Database change node ID

How can I change the naming of the nodes of my children in the image below?
questions_stats is a List<Integer>, I'm aware that I get integers as nodes Id because this is a List. I create each of the children randomly with a number between 0 and 1000. I set this ID as part of the object and to find it I loop trough the list. What I want is to set the "0671" as the Key of the Object at the moment I create it.
How should I define my object in order to access each child with an Id that I define as a String.
Each of the questions_stats is an object.
This is my UserProfile Class definition.
public class UserProfile implements Parcelable {
private List<Integer> questions_list;
private List<QuestionsStats> questions_stats;
private String country_name, share_code, user_name;
private int token_count;
private Boolean is_guest;
public UserProfile() {
}
public UserProfile(List<Integer> questions_list, List<QuestionsStats> questions_stats, String country_name, String share_code, String user_name, int token_count, Boolean is_guest) {
this.questions_list = questions_list;
this.questions_stats = questions_stats;
this.country_name = country_name;
this.share_code = share_code;
this.user_name = user_name;
this.token_count = token_count;
this.is_guest = is_guest;
}
}
I know I can set them using the child("0159").setValue(QuestionStats) individually.
But for my purpose I need to retrieve the data of the "user" as a whole and then iterate whithin questions_stats like it is a List.
How should I define my UserProfile class in order to achieve what I want?
Anybody could give me a hint?
How can I change the node names of my children in the image below?
Answer: There is no way in which you can change the names of the nodes from your Firebase database. There is no API for doing that. What can you do instead is to attach a listener on that node and get the dataSnapshot object. Having that data, you can write it in another place using other names. You cannot simply rename them from 0 to 0000, 1 to 0001 and so on.
Perhaps I should have asked for How to "Set" the node Id instead of "Change"
What I have is an List<QuestionsStats>, but when using an List<QuestionsStats> you get indexes as Keys, What I want is to have the same List<QuestionsStats> but instead of indexes, String Keys for each of my items.
So I changed my List for a Map<String, QuestionsStats>. Now the tricky part is when parceling the Object. You can use readMap() or writeMap() to parcel as shown here in this answer by #David Wasser, but it gives a warning:
Please use writeBundle(Bundle) instead. Flattens a Map into the parcel
at the current dataPosition(), growing dataCapacity() if needed. The
Map keys must be String objects. The Map values are written using
writeValue(Object) and must follow the specification there. It is
strongly recommended to use writeBundle(Bundle) instead of this
method, since the Bundle class provides a type-safe API that allows
you to avoid mysterious type errors at the point of marshalling.
So with the help of the comments in This Question I parceled using this code, note that I'm leaving the "easy" way commented in case somebody find it useful or have any comment on that :
protected UserProfile(Parcel in) {
// in.readMap(myMap, Object.class.getClassLoader());
myMap = new HashMap<>();
String[] array = in.createStringArray();
Bundle bundle = in.readBundle(Object.class.getClassLoader());
for (String s : array) {
myMap.put(s, (Object) bundle.getParcelable(s));
}
}
#Override
public void writeToParcel(Parcel dest, int flags) {
// dest.writeMap(myMap);
Bundle bundle = new Bundle();
for (Map.Entry<String, Object> entry : myMap.entrySet()) {
bundle.putParcelable(entry.getKey(), entry.getValue());
}
Set<String> keySet = myMap.keySet();
String[] array = keySet.toArray(new String[keySet.size()]);
dest.writeStringArray(array);
dest.writeBundle(bundle);
}
Why I want this, well at the moment my list contains less than 100 items but it could grow up to a 1000, I'm no Pro, but I believe that if I already know the key of the item I'm interested in will be always better than having to iterate over the list to find it. In the end my main problem was the usage of a Map, I did not know howto.

Couchbase Lite: reading document vs querying data

I'm switching an Android project to using Couchbase Lite, and I'm confused with ways for fetching the data from the database.
I have a document, which contains only one property:
Map<String, Object> properties = new HashMap<String, Object>();
properties.put("data_key", json);
Document document = database.getDocument("data_doc_id");
document.putProperties(properties);
The next my step is getting the stored data from the database. I found two ways:
The first approach is reading the document
Document doc = database.getDocument("data_doc_id");
String json = (String) doc.getProperty("data_key");
The second one is querying
View view = database.getView("data_json");
view.setMap(new Mapper() {
#Override
public void map(Map<String, Object> document, Emitter emitter) {
if ("data_doc_id".equals(document.get("_id")) {
String json = (String) doc.getProperty("data_key");
emitter.emit("data_key", json);
}
}
}, "1.0");
QueryEnumerator queryEnumerator = view.createQuery().run();
String dataJson = "";
for (QueryRow queryRow : run) {
if ("data_key".equals(queryRow.getKey()) {
json = (String) queryRow.getValue();
}
}
Is it okay to use the first approach to get the stored JSON?
For what cases the second approach should be used? It has far more code than the first one, maybe it has something to do with caching or/and speed/performance? What are the pros and cons of this approach?
The first approach is retrieving the document directly. This is the fastest way to do it.
With databases, though, often you want to retrieve documents based on some feature of the data. To do this you want the ability to create queries about the data. That's what the second approach is for.

Firebase limitToLast (Query) not parsing the response

I am doing a query to get an array from Firebase and everything works fine. The query is the following:
FirebaseDatabase.getInstance().getReference()
.child("results").child("mood")
.child(Preferences.getUserId(this))
.addListenerForSingleValueEvent(new ValueEventListener() {
...
And I noticed the child() chain always returns a DatabaseReference object. However, I wanted to use limitToLast() to get only the last element of this array. I didn't really understand why but it returns a Query instead of a DatabaseReference, but both have the addListenerForSingleValueEvent() method since DbRef extends Query.
FirebaseDatabase.getInstance().getReference()
.child("results").child("mood")
.child(Preferences.getUserId(this))
.limitToLast(1)
.addListenerForSingleValueEvent(new ValueEventListener() {
The problem is that it's not parsing my response as it was with DbRef, and then I get an exception:
com.google.firebase.database.DatabaseException: Expected a List while deserializing, but got a class java.util.HashMap
I looked into the HashMap and it's just a Map of my Object attributes as Strings but not parsed.
Why do Query and DatabaseReference have a different response/deserialization method?
Any help is greatly appreciated.
EDIT: As per requested, that it the code to get the data. It's the same for both cases.
#Override
public void onDataChange(DataSnapshot snapshot) {
GenericTypeIndicator<List<Mood>> t = new GenericTypeIndicator<List<Mood>>() {};
moodList = snapshot.getValue(t);
...do stuff with moodList
Whereas moodList is a List<Mood>
You didn't post the code for your Mood class or a sample of the JSON that is stored at location "mood". I'm assuming that you have defined Mood as a POJO that satisfies the Firebase requirements for getters/setters and default constructor. Also that the value stored at "mood" is a valid array of Mood elements.
When you modify your query with limitToLast(1), Firebase returns a map containing the last Mood in the array. Perhaps you were expecting it to return a List<Mood> with length of one. I don't find the Firebase documentation clear on this point. Perhaps Firebaser Frank can provide more details.
To see more clearly what is returned with limitToLast(1), you can modify your code like this:
public void onDataChange(DataSnapshot snapshot) {
Map<String,Object> map = (Map<String,Object>) snapshot.getValue();
Log.i(TAG, "onDataChange: map=" + map);
}
The output will look like this, where N is the index for the last value in your array:
onDataChange: map={N={<the fields of your Mood POJO here>}}

Categories

Resources