I want to look into a child to look for another child. I want to find my current Uid in someone elses uid. How do I do that?
guard let currentUid = Auth.auth.currentUser?.uid else { return }
guard let (this is missing) = ... else { return }
Database.database().reference().child("users-following").child(" ... ").child(currentUid)
The "this is missing" and child("...") indicate, where I am not getting anywhere. Can someone help me?
I want to look in this child("…") to check and see if my currentUid is in that list.
______ UPDATE _______
"user-followers : {
"YsBqvPlRGMfx..." : {
"iFjaXB7lI..." : 1
}
},
iFjaXB... is the user, that deletes the account. All his data is being deleted as it's supposed to. But the id stays within the YsBq child in the "user-followers". So, I want to delete the child "iFjaXB" in the child of "YsBq". How do I do this?
I got things going. This is how:
Database.database().reference().child("here you put the one, that stores your currentUid".child(currentUid).observe(.childAdded) { (snapshot) in
let key = snapshot.key
Database.database().reference().child("user-followers).child(key).child(currentUid).removeValue()
Related
I have a social app that I want display to the user the posts that were most recently liked and who were the two most recent people to like that post. Displaying something like "User A and User B liked and 31 others liked your post" where the 31 others liked the post less recently than User A and User B and this specific post was the most recent post of the user's to be liked.
I am trying to figure out the best way to structure firebase given these requirements. I was thinking I would store the lastLiked timestamp associated to the post in likeActivity and then use the timestamp as the key for the users who liked the post (see below).
"likeActivity" : {
"nIhx1SnChjapy4cbrD5sC1WIZXM2" : {
"-M0egnxw7TqEJoEwA0gG" : {
"lastLiked" : 1582337525620,
"userLikes" : {
"1582337525616" : "BmvRlWWuGRWApqFvtT8mXQlDWzz2",
"1582337525620" : "Ff0CxZhQzYVHuqbnsiOKwRAB01D2"
}
},
"-M0jMrisNrnB4usGeCaS" : {
"lastLiked" : 1582337525630,
"userLikes" : {
"1582337525630" : "Ff0CxZhQzYVHuqbnsiOKwRAB01D2"
}
},
"-M0jPBatN45YtfdyTXNM" : {
"lastLiked" : 1582337525616,
"userLikes" : {
"1582337525610" : "bz2E02wmmXQjVkxRF23T2SPkzSf2",
"1582337525616" : "WPOThFRRLDUCeJ8YVmyHFpGgnxI3"
}
}
}
}
Would this be the best way given my requirements from above? If so, I am having a ton of trouble retrieving these for my iOS app because when I call snapshot.children.allObjects I am not just getting the likes but also the lastLiked timestamp. How would I re-work the observeActivity function to pull data ordered by lastLiked and then ordered by timestamp. I read the documentation on ordering data in Firebase but I'm unsure how to apply it in my circumstance.
func observeActivity () {
guard let uid = Auth.auth().currentUser?.uid else {
return
}
let newActivity = DataService.ds.REF_LIKE_ACTIVITY.child("\(uid)")
newActivity.observe(.value, with: {(snapshot) in
self.posts = []
if let snapshot = snapshot.children.allObjects as? [DataSnapshot] {
for snap in snapshot{
let postKey = snap.key
//self.posts.append(snap.key)
let userLikeData = newActivity.child("\(snap.key)").child("userLikes")
userLikeData.observe(.value, with: {(snapshot) in
if let newSnap = snapshot.children.allObjects as? [DataSnapshot] {
for valueSnap in newSnap {
//Users who have liked the post
print("SNAPTIVITY \(valueSnap.value!)")
let userId = valueSnap.value!
//self.userArray.append("\(userId)")
if self.activityDict["\(postKey)"] != nil {
self.activityDict["\(postKey)"]!.append("\(userId)")
} else {
self.activityDict["\(postKey)"] = ["\(userId)"]
}
}
let postData = DataService.ds.REF_POSTS.child(postKey)
postData.observe(.value, with: { (snapshot) in
if let postDict = snapshot.value as? Dictionary<String, AnyObject> {
let key = snapshot.key
let post = Post(postKey: key, postData: postDict, isLiked: 0)
self.posts.append(post)
}
//self.feedTableView.reloadData()
self.activityTableView.reloadData()
})
}
})
}
}
})
}
In most social network application each user can only like an individual post at most once. Your current data model for these likes is:
"userLikes" : {
"1582337525616" : "BmvRlWWuGRWApqFvtT8mXQlDWzz2",
"1582337525620" : "Ff0CxZhQzYVHuqbnsiOKwRAB01D2"
}
This model allows a single user to like the same post multiple times. And while you can prevent this from happening in your application code, there's no way to enforce it in security rules.
For this reason, a pretty hard rule when modeling data in Firebase&Firestore is: if something must be unique, it must be the key of the child node/document.
So based on that, I'd model this fragment as:
"userLikes" : {
"BmvRlWWuGRWApqFvtT8mXQlDWzz2": 1582337525616,
"Ff0CxZhQzYVHuqbnsiOKwRAB01D2": 1582337525620
}
You'll note that this now also allows you to store the timestamp as a number, which prevents all kind of possible sorting problems down the line.
I assume your data structure is:
likeActivity
$uid
$postId: ...
Since you're retrieving a list of posts for the current user, you can only order the resulting posts on values that are at a fixed path under each post.
So you can sort the posts on their lastLiked, but you can't then determine the order in which the userLikes under that are returned. You'll have to reorder those results in your application code to determine the most recent like(r).
I don't know how to get data from Firebase to my UITableView. All tutorials I have been watching used Firebase Authentication, in their videos all worked out fine but while trying to replicate it, I failed.
Here is what I tried:
First there is my Database struct:
And here is my code:
func observePosts(){
let postsRef = Database.database().reference().child("posts")
postsRef.observe(.value, with: { snapshot in
var tempPosts = [Post]()
for child in snapshot.children {
if let childSnapshot = child as? DataSnapshot,
let dict = childSnapshot.value as? [String:Any],
let text = dict["text":""] as? String
{
let post = Post(text: text)
tempPosts.append(post)
}
}
self.posts = tempPosts
self.tableView.reloadData()
})
}
So my question is: How do I get for example the message from a database structure like this?
let text = dict["text":""] as? String {
let post = Post(text: text)
tempPosts.append(post) }
This is wrong. There is nothing like dict["text":""] . First you dont have any data for text keyword , Second you dont write this :""] , you can call as dict["text"].
I think you solution is let text = dict["title"] as? String . But you architecture is wrong. You can declare just one keyword . title 1 , title 2 is wrong. You have to set just title.
If you have followed YouTube tutorials, there's a high chance you did not modify your firebase rules to reflect on non-authenticated users. If you didn't, Firebase ignores every read/write request. To enable this, Edit your firebase rules by:
Set the rules to TRUE
{
"rules": {
".read": true,
".write": true
}
}
However, there's more to it. Don't do it this way unless you're in test mode. Google has some nice docs about it:
Visit https://firebase.google.com/docs/database/security to learn more about security rules.
i was trying to write a code to pull a data from the realtime database using observe for child changed. But i don't know what the mistake is but the code fails. From my debugging study, i found that the observe was successfully triggered when the value changed, but it fails when i try to get the snapshot value to a variable. How should data be retrieved in a observe for child change case.
func userBalance() {
DatabaseProvider.Instance.userRef.child(UserDataHandler.Instance.user_id).observe(FIRDataEventType.childChanged, with: { (snapshot) in
print("Snapshot: ", snapshot)
print("Snapshot Value", snapshot.value)
guard let data = snapshot.value as? NSDictionary else {
print("checkpoint fail test")
return
}
guard let userBalance = data[Constants.BALANCE] as? String else { return }
// update UserDefaults
userDefault.setString(userBalance, forKey: "userBalance")
//update local session
UserDataHandler.Instance.balance = userBalance
}) }
kindly help me out, thanks in advance.
Debugging Data :
Snapshot: Snap (balance) 100
Snapshot Value Optional(100)
checkpoint fail test
Thanks guys, i found the answer, may be it will help someone else. I am put down the new code that worked.
DatabaseProvider.Instance.userRef.child(UserDataHandler.Instance.user_id).observe(FIRDataEventType.childChanged, with: { (snapshot) in
guard let key = snapshot.key as? String else { return }
guard let value = snapshot.value as? String else { return }
if key == Constants.BALANCE {
guard let userBalance = value as? String else { return }
// update UserDefaults
userDefault.setString(userBalance, forKey: "userBalance")
//update local session
UserDataHandler.Instance.balance = userBalance
}
}) }
The problem was that the observe detects the change in the database as one by one, so the snapshot comes as a single data for every change, if you change multiple values in a go, the observe detects it as multiple changes, one by one with each change as change of one value. So when i changed it to direct string it worked. You were right #Achref Gassoumi the problem was with the cast. Just after you told about it, i tried it out. Thanks.
I think your problem probably is with the cast
try the following :
DatabaseProvider.Instance.userRef.child(UserDataHandler.Instance.user_id).observe(FIRDataEventType.childChanged, with: { (snapshot) in
guard let data = snapshot.value as? [<String,anyObject>] else {
print("checkpoint fail test")
return
}
print (data)
I posted a question previously regarding how to access data inside a child snapshot, where I got a very well-working answer. However, this solution only allowed me to retrieve the data by value - and not my child. You see, I had a JSON tree-structure like this:
Players {
PlayerID {
Username
Rank
Achievements {
Rookie: yes
}
}
And then I realized that I really need multiple 'childByAutoId' under the 'Achievements' - that will look something like this:
Player {
PlayerID {
Username
Rank
Achievements {
autoID1 {
isAchieved: yes
}
autoID2 {
isAchieved: yes
}
}
}
So how would I go on trying to grab the very ChildValues of each childByAutoId? I know for a fact that this works with the 'ChildAdded' on observe Snapshot, however - this doesn't seem to be a feature here.
Here is the code I have right now:
if let childSnapshot = snapshot.childSnapshot(forPath: "Achievements") as? FIRDataSnapshot{
if let achievementDictionary = childSnapshot.value as? [String:AnyObject] , achievementDictionary.count > 0{
if let achieveMedal = achievementDictionary["Rookie"] as? String {
print(achieveMedal)
}
}
}
Help would be greatly appreciated!
How about a JSON tree structure like this:-
Achievements : {
achievement1 : true,
achievement2 : true,
achievement3 : false,
achievement4 : true,
}
For retrieving your achievements:-
if let childSnapshot = snapshot.childSnapshot(forPath: "Achievements") as? FIRDataSnapshot{
if let achievementDictionary = childSnapshot.value as? [String:AnyObject] , achievementDictionary.count > 0{
for each in achievementDictionary{
print(each.0) // achievement name
print(each.1) // isAchieved (true/false)
}
}
}
}
It's not advisable to add such deep nodes in your DB for navigation reason's .
But this code will also work for the childByAutoID case, i.e each.0 will be your autoID AND each.1 will become that id's corresponding dictionary.For deeper details of that dictionary just navigate through the dictionary
Hello I am using firebase on swift and having an issue with .exist()
I am trying to do a query and check for a value, if its there I do nothing, if it isn't I add it to the list. I am just trying to avoid duplicating data this way. Heres the code:
InfoCenter.ref.child("users/\(InfoCenter.userId)/following").queryOrderedByValue()
.queryEqualToValue(firstTextField.text)
.observeEventType(.Value, withBlock: { snapshot in
if snapshot.exists(){
self.displayAlert("You already follow that person!", Title: "Whoops")
print(snapshot.value!)
} else {
InfoCenter.ref.child("users/\(InfoCenter.userId)/following").childByAutoId().setValue(TheId)
InfoCenter.ref.child("users/\(TheId)/followers").childByAutoId().setValue(InfoCenter.userId)
print(snapshot.value!)
}
})
so to me everything looks right, but when it runs snapshot.exist() always returns false but when I print snapshot.value! I get null with arrows around it (I couldn't type the arrows because SO thought it was a tag then) . So I'm confused.. how is null considered exists? Can someone please show me what to change to fix this? Thanks!!
Edit:
To be clear following is a list of users. So with in following are autoId's that have links to other users. The whole purpose of the above query is to go through the autoId's and make sure that this person does not already follow that person. Here is a snapshot of the data structure I am trying to explain:
Can I suggest an alternative? This solution reads the value as the location in question. Big benefit here is that there's no query overhead.
Assume we want to see if we follow frank and if not, follow him.
let ref = InfoCenter.ref.child("users/\(InfoCenter.userId)/following")
ref.observeSingleEventOfType(.Value, withBlock: { snapshot in
if let person = snapshot.value as? String {
if person == "frank" {
print("you are following frank: creeeeepy")
} else {
print("you are not following frank, follow him")
}
} else {
print("node doesnt exist")
}
})
this will directly read the value at
users/some_user_id/following: "the value that's read (frank in this case)"
Edit: based on an updated question, the 'following' node should look like
users
your_uid
following
some_user_you_are_following_uid: true
another_user_you_are_following_uid: true
then you are simply checking to see if the path exists
let ref = InfoCenter.ref.child("users/\(InfoCenter.userId)/following")
let theUserRef = ref.child("some_user_you_are_following_uid")
theUserRef.observeSingleEventOfType(.Value, withBlock: { snapshot in
I think your query might not be be working user InfoCenter.userId might be an optional force unwrap and see if that return the snapshot.