Firebase Database multiple strings in one child - firebase

im working with firebase for a couple months and so far i had no issues until now. im using kotlin and my problem is simple but i cant find a way out. i storage strings in database: path"/user/friends" , but i cant change the variable name and the strings were overwriting itselves. My solution was use "push()" until the "setValue()", but with this i have the following firebase structure:
"users": {
"yvrYpjMwVSPBvMAvDGo26hPlWWQ2": {
"email": "vinibarros.sp#gmail.com",
"friends": {
"-LfD9z6ke7FXFjxUb4td": {
"email": "teste#gmail.com"
},
"-LfDA-NaAYAMoWiPhXy4": {
"email": "teste2#gmail.com"
}
},
"primeiroLogin": true,
"stars": 0,
"tutorialComplete": false,
"uid": "yvrYpjMwVSPBvMAvDGo26hPlWWQ2",
"username": "Vinicius Barros"
}
}
basically hashmaps inside a hashmap ps:lol mindblow
how do i get the pushcode.value into an arraylist?
i have a class user that have the friend variable, until now this variable was typed as hashMap. and the call to get the email was "user.friends.value"
this worked because was one friend....
com.google.firebase.database.DatabaseException: Failed to convert value of type java.util.HashMap to String
When I added more than one user I got this error that references my class user, where have a "hashMap". But the firebase gives me another hashmap instead of string. I was thinking about: hashMap<hashMap<String,String>, null>.
i 've tried this:
class friends:
#Parcelize
class Friend(val hashMap: HashMap < String, String > ? ): Parcelable {
constructor(): this(null)
}
The activity where i show the friends:
val ref2 = FirebaseDatabase.getInstance().getReference("/users/" + cUid + "/friends/")
ref2.addListenerForSingleValueEvent(object: ValueEventListener {
override fun onCancelled(p0: DatabaseError) {
}
override fun onDataChange(p0: DataSnapshot) {
p0.children.forEach {
val friend = it.getValue(Friend::class.java)
Log.d("teste", it.toString())
if (friend != null) {
Log.d("teste", friend.hashMap ? .values.toString())
//friends.add(friend.hashMap?.values.toString())
}
}
}
})
this keeps returning null....

With your Friend class, the Firebase client looks for a JSON for each friend with this structure:
"-LfD9z6ke7FXFjxUb4td": {
"hashMap": {
...
}
},
This is because you're defining your Friend class with a property hashMap like this: class Friend(val hashMap: HashMap < String, String > ? ).
To be able to read your current structure, you'll need to define a data class like this:
data class Friend (
val email: String? = null
}
Now the email in the Friend class matched the email property in the JSON. And since email has a default value, the Friend class will have a default no-argument constructor, which Firebase relies on.

Solved!
After get into /friends
i did this:
var friends : ArrayList<String> = arrayListOf()
the onDataChanged where i get the string friend
override fun onDataChange(p1: DataSnapshot) {
p1.children.forEach { it1 ->
val friend = it1.value as String
friends.add(friend)
}
}

Related

How go get both both key and value from firebase database on kotlin

I'm new to android development and im having a bit of problem with firebase database. I'm creating a app somewhat similar to e-commerce application.
category1
child1
name: nameOfChild1
value: value
child2
name: nameOfChild2
value: value
child3
This is how my database is structured. im using
dbref = FirebaseDatabase.getInstance().getReference("requiredCategory")
dbref.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()) {
for (productSnapshot in snapshot.children) {
val product = productSnapshot.getValue(Product::class.java)
productlist.add(product!!)
}
productrecyclerview.adapter = productAdapter(productlist)
}
}
And Product class is
data class Product(
var id: String? = null,
var price: String? = null,
)
Instead i would like to change my structure to
category1
child1
nameOfNested1: value
nameOfNested2: value
child2
nameOfNested1: value
nameOfNested2: value
child3
nameOfNested1: Value
nameOfNested2: value
category2
child1
child2
child3
I want to retrive both the key: nameOfNested and value:value .How do i go on and change the code get both the id and value?
Thanks in Advance
If you also want to get the key of each product, you can do so with:
for (productSnapshot in snapshot.children) {
val key = productSnapshot.key // 👈
val product = productSnapshot.getValue(Product::class.java)
...
Let me answer with what i got working and also be a bit more specific about what i was trying to accomplish
First of all, let me start with what i was doing. i had a Firebase Realtime Database that looked like this
(Only an example for demonstration purpose)
Students
Riya
name: Riya
class: 10
Benson
name: Benson
class: 9
Merlin
name: Merlin
class: 7
I Made a student class that looks like this
data class Student(
var name: String? = null,
var class: String? = null,
)
I found a snippet online that would retrieve data from db that is given below
dbref = FirebaseDatabase.getInstance().getReference("Students")
dbref.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()) {
for (studentSnapshot in snapshot.children) {
val student = studentSnapshot.getValue(Student::class.java)
studentlist.add(student!!)
}
myrecyclerview.adapter = thisAdapter(studentlist)
}
}
It gave a Array that look something like this
[Student(name=Riya, class=10), Student(name=Benson, class=9), Student(name=Merlin, class=7)]
As you can see, the structure that i was using was inefficient and i want to change it. Also, instead of a single Students refence i wanted to add child which holds the students based on the class they are in. Also i wanted to add age property to each student as well. So i came up with a structure that looks like this
Students
Class7
Joe: 12
Mary: 11
Ann: 12
Class8
Michael: 12
Lucy: 12
Class9
Ricko: 15
Anna: 14
Staff
class7
Janet:25
Bob: 34
What i was having issue with getting Both the Key and value at the same time. what at the time i was using was
FirebaseDatabase.getInstance()
.getReference("Students")
.child(requiredClass)
.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()) {
for (studentSnapshot in snapshot.children) {
val student = studentSnapshot.getValue(Student::class.java)
studentlist.add(student!!)
}
It was not working with what i had.. It was looking for ids name and age. (i renamed the class to age in the Student class)
I got it working by doing something like this
FirebaseDatabase.getInstance()
.getReference("Students")
.child(requiredClass)
.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()) {
for (studentSnapshot in snapshot.children) {
val student = Student()
student.name = studentSnapshot.key.toString()
student.age = studentSnapshot.value.toString()
studentlist.add(student!!)
}
This works fine and returns a array that i wanted.
I know most of that explanation was unnecessary. i wanted to clarify what my situation was. Also my solution might be the worst. If anyone have a better solution, i'm all ears...

Convert Firebase DocumentSnapshot data to a custom Scala (or Java) class

I'm using Firebase for a private Scala project and I'm struggling to understand how I can manage Firebase responses if I want to avoid using HashMap.
This is the information that I'm trying to manage:
These are the two Scala classes that I wrote with the idea to use them along with the toObject method:
class Doc() {
#BeanProperty val map: util.HashMap[String, Value] = new util.HashMap[String, Value]()
}
class Value() {
#BeanProperty val displayName: String = ""
#BeanProperty val email: String = ""
// Extra fields that I need to initialize in the Scala code
#BeanProperty val totalLogins: Int = 0
#BeanProperty val todoMap: util.HashMap[String, String] = new util.HashMap[String, String]()
#BeanProperty val todoList: util.ArrayList[String] = new util.ArrayList[String]()
#BeanProperty val totalChanges: Int = 0
#BeanProperty val totalErrors: Int = 0
}
And this is snapshot listener implementation that I wrote:
docFirebase.addSnapshotListener(new EventListener[DocumentSnapshot]() {
override def onEvent(snapshot: DocumentSnapshot, e: FirestoreException): Unit = {
if (e != null) {
println("[OnSnapshot] Listen failed: " + e)
return
}
if (snapshot != null && snapshot.exists) {
val doc = snapshot.toObject(classOf[Doc])
// Here below I'll write the complex logic I need ...
} else {
println("[OnSnapshot] Current data: null")
}
}
})
Using that code I'm always getting an empty HashMap into the doc variable. Can someone helps me understand what I misunderstood about reading data from Firebase ? Thanks in advance.
All of your properties in the document are nested under an object called "abc". That fact is not reflected in your code - you need to call out abc by name to get all the nested fields from it. You probably don't want that nesting at all. Just put all the fields (displayName, email, etc) as top-level fields in the document.

How to work with nested Models in Sqlflite Flutter

I am going to be working with sqlflite package in Flutter, and I have been reading a lot about it. However, everywhere I find the example being shown for the single model, that is
SingleModel{
String data1, data2;
....
}
I have followed
Store list of objects in sqlite
Sqlflite operation in Flutter
these as well, but that did not quite resolve it. My main requirements is to work with the data like this:
user: {
'id': unique_key,
'name': 'abc',
'courses': [
{ 'coursename': 'some_coursename'},
{ 'coursename': 'some_other_coursename'}
]
}
I have designed my model correctly,
UserModel Class
class UserModel{
int id;
String name;
List<Course> _courses;
UserModel.set(Map data){
this.id = data['id'];
this.name = data['name'];
if(data['courses'] != null)
this.courses = [data['courses']];
}
// append more courses
void setMorCourses(Map course){
// checking for duplicate errors
if(!this.courses.contains(course['course']))
this.courses.add(course['course'])
}
}
Now, I am confused on how to use the Nested Model with sqlflite. I believe I need to work in the DatabaseHelper class.
Course Class
class CourseModel{
String coursename;
CourseModel.set(Map data){
this.coursename = data['coursename'];
}
}

How to retrieve a field in firebase with user id

I am implementing a quiz app in Android studio using kotlin. I am communicating with firebase where I store users who signs up. This is how it is structured in firebase:
And this is how I save a user when they signed up:
class User(val uid: String, val Username: String, var highscore: Int)
private fun saveUserToDatabase(){
val uid: String? = FirebaseAuth.getInstance().uid
val ref: DatabaseReference = FirebaseDatabase.getInstance().getReference( "/Users/$uid")
val user = User(uid.toString(), signUpUsername.text.toString(), 0)
ref.setValue(user)
.addOnSuccessListener {
Log.d("RegisterActivity", "User was saved in the database")
}
}
}
When a user has logged in and have played a round I want to retrieve the highscore with the current users userId and update the highscore if the score is greater than the highscore. This is my function that handles that:
private fun updateScore(score: Int, userId: String, isLoggedIn: Boolean){
if(isLoggedIn) {
var ref = FirebaseDatabase.getInstance().reference
ref.child(userId).addListenerForSingleValueEvent(object : ValueEventListener {
override fun onCancelled(error: DatabaseError) {
Log.e("onCancelledError", "onCancelled", error.toException())
}
override fun onDataChange(dataSnapShot: DataSnapshot) {
var highscore = dataSnapShot.child("highscore").getValue(Int::class.java)
Log.d("highscore", highscore.toString())
if(highscore != null){
if (highscore < score) {
highscore = score
dataSnapShot.ref.setValue(highscore)
}
}
}
})
}
}
But this does not work because highscore is null, when it should be 0. My userId is right so it is not that, I do not know what is wrong. Since I am new to firebase I have a hard time understanding the syntax. Any suggestions what could be wrong?
Thanks!
You're not building the reference to the user's node correctly. You probably meant to do this:
ref.child('Users').child(userId).addListenerForSingleValueEvent(...)
Note child('Users').

How to parse a Spring 5 WebClient response in a non-blocking way?

I'm using Spring WebFlux WebClient to retrieve data from an external API, like this:
public WeatherWebClient() {
this.weatherWebClient = WebClient.create("http://api.openweathermap.org/data/2.5/weather");
}
public Mono<String> getWeatherByCityName(String cityName) {
return weatherWebClient
.get()
.uri(uriBuilder -> uriBuilder
.queryParam("q", cityName)
.queryParam("units", "metric")
.queryParam("appid", API_KEY)
.build())
.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(String.class);
}
This works fine and produces a response like this:
{
"coord":{
"lon":-47.06,
"lat":-22.91
},
"weather":[
{
"id":800,
"main":"Clear",
"description":"clear sky",
"icon":"01d"
}
],
"base":"stations",
"main":{
"temp":16,
"pressure":1020,
"humidity":67,
"temp_min":16,
"temp_max":16
},
"visibility":10000,
"wind":{
"speed":1,
"deg":90
},
"clouds":{
"all":0
},
"dt":1527937200,
"sys":{
"type":1,
"id":4521,
"message":0.0038,
"country":"BR",
"sunrise":1527932532,
"sunset":1527971422
},
"id":3467865,
"name":"Campinas",
"cod":200
}
But I'm only interested in the "temp" property (main -> temp). How could I transform the response (using Jackson's ObjectMapper, for example) to return only "temp" value in a reactive/non-blocking way?
I understand the first thing is replacing ".retrieve()" by ".exchange()" but I can't figure out how to make it work.
PS: This is my first question here. Please let me know if I'm doing something wrong or if you need more details.
Thanks!
You need to create a type that corresponds to the response sent by the server. A very minimal example could be like this:
#JsonIgnoreProperties(ignoreUnknown = true)
public class WeatherResponse {
public MainWeatherData main;
}
and the MainWeatherData class could be:
#JsonIgnoreProperties(ignoreUnknown = true)
public class MainWeatherData {
public String temp;
}
Finally, you could use WeatherResponse in bodyToMono:
...
.retrieve()
.bodyToMono(WeatherResponse.class);
The #JsonIgnoreProperties(ignoreUnknown = true)annotation instructs Jackson to not give any errors if it encounters any value in JSON string that is not present in you POJO.
You can access the WeatherResponseobject with a chained map operator:
getWeatherByCityName(cityName)
.map(weatherResponse -> weatherResponse.main.temp)

Resources