Ok, so this is what my Fireabse database looks like:
Now I need to update the "about" node for every user. Without the user node, this is what I would do:
val mAllUserDatabase : DatabaseReference = FirebaseDatabase.getInstance().reference.child("Users"))
val childUpdates = HashMap<String, Any>()
childUpdates["/about"] = "new value"
mAllUserDatabase.updateChildren(childUpdates)
The problem is, I need to define the node of the user (don't I?). But since the user node all have a different name, I would need something like "any- node" or "all nodes". Something like
childUpdates["/any/about"] = "new value"
or getChildren()of the snapshots.
What would be the best way to solve this? Do I have to use addListenerForSingleValueEvent to read the names of all nodes and then use the names on mAllUserDatabase with .updateChildren(childUpdates)? That cant be the best way to do this.
To update your about property within all user objects, please use the following lines of code:
val rootRef = FirebaseDatabase.getInstance().reference
val usersRef = rootRef.child("Users")
val valueEventListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
for (ds in dataSnapshot.children) {
val childUpdates = HashMap<String, Any>()
childUpdates["about"] = "yourNewAboutValue"
ds.ref.updateChildren(childUpdates)
}
}
override fun onCancelled(databaseError: DatabaseError) {
Log.d(TAG, databaseError.getMessage()) //Don't ignore errors!
}
}
usersRef.addListenerForSingleValueEvent(valueEventListener)
To write a value to a node in the Firebase Realtime Database you need to know the exact path to that node. Firebase does not have the concept of SQL's update queries.
So in your case you'll need to first read the nodes you want to update, then loop over them, and then update them either one by one or with one big multi-location update statement.
Related
I'm saving an id to Firebase Realtime Database like this:
binding.ivStar.setOnClickListener {
firebaseDb.getReference("Users").child(uid).child("movie").push()
.setValue(args.movie?.id)}
And I need to check if this id exists in Firebase. And I did like this:
private fun checkData() {
val postRef = firebaseDb.getReference("Users").child(uid).child("movie")
postRef.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists()) {
Log.e("Fragment", "${args.movie?.title} exists")
} else {
Log.e("Fragment", "${args.movie?.title} not exists")
}
}
override fun onCancelled(error: DatabaseError) {
Log.e("Fragment", error.toString())
}
})
}
Every time I check, it returns movie exists even if I don't save it. Where am I doing wrong?
every time I check, it returns a movie exists even if I don't save it.
This is happening because when you attach a listener to the following reference:
val postRef = firebaseDb.getReference("Users").child(uid).child("movie")
It checks if the movie node exists, and not a particular movie. Since under that node, most likely there are multiple movies, snapshot.exists() will always return true. If you want to check the existence of a particular movie, you need to add the corresponding ID to the reference:
val postRef = firebaseDb.getReference("Users")
.child(uid)
.child("movie")
.child("movieIdFromDatabase") //👈
Where movieIdFromDatabase should be the ID from the database, the one that starts with -.
try snapshot.getValue<>() and then check if this value is null or not maybe that help
The code
This is our code, we just want to display the current user's key, that's it so how should we do that.
Currently, the code gives the output of all the keys and not the current user key.
As output, we are getting the values: Asif, Test24, and Vaishnavi in the variable key
The image is of the Realtime Database The image of Realtime Database
To solve this issue, you need to use a query. In Kotlin, the code should look like this:
val uid = FirebaseAuth.getInstance().currentUser?.uid
val db = FirebaseDatabase.getInstance().reference
val usersRef = db.child("Users")
val queryByUid = usersRef.orderByChild("uid").equalTo(uid)
val valueEventListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
for (ds in dataSnapshot.children) {
val key = ds.getKey()
Log.d("TAG", key)
}
}
override fun onCancelled(error: DatabaseError) {
Log.d("TAG", error.getMessage()) //Never ignore potential errors!
}
}
queryByUid.addListenerForSingleValueEvent(valueEventListener)
If for example,e the authenticated user is Asif, then the result in the logcat will be:
KYGf ... uSP2
Always remember to add all necessary keys when you create a reference. Never use .child(""), which is an empty string.
I'm working on an application in kotlin for sending an image to a random user or to multiple user from firebase. My database is structured like this :
Users
bVk3KBL81AY2LUVUbC6G1qcLAcl2
username : test
uid : bVk3KBL81AY2LUVUbC6G1qcLAcl2
And I don't know how to get a random user from firebase, I searched but I don't find the best solution for my structure.
I try with this post : How to get unique random product in node Firebase?
But the code doesn't work I have multiple errors
Thank you in advance to any one who may be able to give me some solutions.
Edit #1
I've worked on it and it's working, but I don't know how limit the random to 3 users for example.
In my application the user can change the limit of user so I need to change the random limit.
My code :
fun chooseRandomUser() {
val rootRef = FirebaseDatabase.getInstance().getReference()
val productsRef = rootRef.child("users")
val valueEventListener: ValueEventListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
val productList = ArrayList<String?>()
for (ds in dataSnapshot.children) {
val name = ds.child("username").getValue(String::class.java)
productList.add(name)
Log.d("FragmentActivity", "usernames : $name")
}
val productListSize = productList.size
val randomProductList = ArrayList<kotlin.Int>()
randomProductList.add(Random().nextInt(productListSize))
Log.d("FragmentActivity", "list : $randomProductList")
}
override fun onCancelled(databaseError: DatabaseError) {
Log.d("FragmentActivity", "Error: ${databaseError.message}")
}
}
productsRef.addListenerForSingleValueEvent(valueEventListener)
}
As far as I could understand, you want to pick a random user from all the list of users that you have in your firebase database. You can simply do that on the android side.
I think you already know how to get all the users from the firebase database. Store the users in a list. Then I would try to come up with a random function which could give me an index of the list randomly and I could pick that user from the list based on that random index.
The same implementation can go for selecting multiple users from that list as well.
I hope that helps.
I am wondering if it is possible to apply multiple queries for the Firebase database in Android/Kotlin.
I have a firebase database that has time value in it.
what I need to get is I want to have sales report hourly based. I get this for 1 hour but, when I try it for another hour I don't get the result. I believe I am doing something wrong here logically.
val rootRef = FirebaseDatabase.getInstance().reference
val query1 = rootRef.child("Sales").orderByChild("time").startAt("00:00:00").endAt("00:30:00")
val query2 = rootRef.child("Sales").orderByChild("time").startAt("23:30:00").endAt("00:00:00")
val valueEventListener = object : ValueEventListener {
override fun onDataChange(p0: DataSnapshot) {
if (p0.exists()) {
for(ds in p0.children) {
var timeList = arrayListOf<String>()
val time = ds.child("time").getValue(String::class.java)!!
var totalList = arrayListOf<Double>()
timeList.add(time)
println("time List : "+timeList)
}
}
}
override fun onCancelled(databaseError: DatabaseError) {
Log.d(TAG, databaseError.getMessage()) //Don't ignore errors!
}
}
query2.addListenerForSingleValueEvent(valueEventListener)
query1.addListenerForSingleValueEvent(valueEventListener)
Can anyone help me to understand the logic here?
Thanks.
......
Edited part:
Here it is what i have done: I am now saving date in miliseconds format as you suggested. And, my code looks like this :
`val query1 = rootRef.child("Sales").orderByChild("time").startAt(1577192700000).endAt(1577192701167)
val valueEventListener = object : ValueEventListener {
override fun onDataChange(p0: DataSnapshot) {
if (p0.exists()) {
for(ds in p0.children) {
var timeList = arrayListOf<Long>()
val time = ds.child("time").getValue(Long::class.java)!!
// var totalList = arrayListOf<Double>()
timeList.add(time)
println("time List : "+timeList)
}
}
}`
when I use miliseconds (long value) as startAt() paramater it gives me error.
I get this for 1 hour but, when I try it for another hour I don't get the result.
The problem in your code is that you are passing strings to the startAt() and endAt() methods. Strings are ordered lexicographically, meaning that the following query:
val query1 = rootRef.child("Sales").orderByChild("time").startAt("00:00:00").endAt("00:30:00")
Will work since 00:30:00 is after 00:00:00 but the second query:
val query2 = rootRef.child("Sales").orderByChild("time").startAt("23:30:00").endAt("00:00:00")
Will not return any results. To solve this, you should store the time as a timestamp and not as a String. To achieve this, please see my answer from the following post:
How to save the current date/time when I add new value to Firebase Realtime Database
In the end, just pass timestamps (long values) to both startAt() and endAt() methods and your problem will be solved.
This is the model I upload on Firebase:
public class OnlineMatch{
private User user1;
private User user2;
public OnlineMatch(User firstPlayer, User secondPlayer) {
this.user1 = firstPlayer;
this.user2 = secondPlayer;
}
}
Then I send data to Firebase in this way (kotlin):
fun createMatch(match: OnlineMatch) {
val matchList = database.child("multiplayer").push()
matchList.setValue(match)
}
Thus, my DB structure is the following:
If I expand a node I can see perfectly my objects: OnlineMatch(User1, User2)
Now I would like to query the db and obtain an ArrayList'<'OnlineMatch'>'.
I have already found the Firebase docs but I found nothing useful.
How can I do? Thanks in advance.
You did not find something useful because when you query against a Firebase database you get a Map and not ArrayList. Everything in Firebase is structured as pairs of key and value. Using an ArrayList is an anti-pattern when it comes to Firebase. One of the many reasons Firebase recommends against using arrays is that it makes the security rules impossible to write.
In Kotlin there is no need for getters and setters. Is true that behind the scenes those functions exists but there is no need to explicitly define them. To set those fields, you can use the following code:
val onlineMatch = OnlineMatch() //Creating an obect of OnlineMatch class
onlineMatch.user1 = userObject //Setting the userObject to the user1 field of OnlineMatch class
//onlineMatch.setUser(userObject)
As you probably see i have commented the last line because there is no need to use a setter in order to set a userObject.
And very important, don't forget to add the no argument constructor in your OnlineMatch class that is needed for Firebase.
public OnlineMatch() {}
Edit:
To actually get the data, just put a listener on the desired node and get the data out from the dataSnapshot object into a HashMap.
val map = HashMap<String, OnlineMatch>()
Then simply iterate over the HashMap like this:
for ((userId, userObject) in map) {
//do what you want with them
}
Or simply use the code below:
val rootRef = firebase.child("multiplayer")
rootRef.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onCancelled(error: FirebaseError?) {
println(error!!.message)
}
override fun onDataChange(snapshot: DataSnapshot?) {
val children = snapshot!!.children
children.forEach {
println(it.toString())
}
}
})
Hope it helps.